mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
Merge remote-tracking branch 'origin/support/3.2' into develop
# Conflicts: # tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php
This commit is contained in:
@@ -3439,8 +3439,18 @@ EOF
|
||||
}
|
||||
$sInputType = '';
|
||||
$sInputId = 'att_'.$iFieldIndex;
|
||||
$value = $this->Get($sAttCode);
|
||||
$sDisplayValue = $this->GetEditValue($sAttCode);
|
||||
if ($oAttDef instanceof AttributeDateTime && !$oAttDef->IsNullAllowed() && $value === $oAttDef->GetNullValue()) {
|
||||
$value = $oAttDef->GetDefaultValue($this);
|
||||
if ($value !== $oAttDef->GetNullValue()) {
|
||||
// Set default date
|
||||
$this->Set($sAttCode, $value);
|
||||
$sDisplayValue = $this->GetEditValue($sAttCode);
|
||||
}
|
||||
}
|
||||
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,
|
||||
$this->Get($sAttCode), $this->GetEditValue($sAttCode), $sInputId, '', $iExpectCode,
|
||||
$value, $sDisplayValue, $sInputId, '', $iExpectCode,
|
||||
$aArgs, true, $sInputType);
|
||||
$aAttrib = array(
|
||||
'label' => '<span>'.$oAttDef->GetLabel().'</span>',
|
||||
|
||||
@@ -6372,7 +6372,11 @@ class AttributeDateTime extends AttributeDBField
|
||||
$oFormField = parent::MakeFormField($oObject, $oFormField);
|
||||
|
||||
// After call to the parent as it sets the current value
|
||||
$oFormField->SetCurrentValue($this->GetFormat()->Format($oObject->Get($this->GetCode())));
|
||||
$oValue = $oObject->Get($this->GetCode());
|
||||
if ($oValue === $this->GetNullValue()) {
|
||||
$oValue = $this->GetDefaultValue($oObject);
|
||||
}
|
||||
$oFormField->SetCurrentValue($this->GetFormat()->Format($oValue));
|
||||
|
||||
return $oFormField;
|
||||
}
|
||||
@@ -6458,8 +6462,20 @@ class AttributeDateTime extends AttributeDBField
|
||||
|
||||
public function GetDefaultValue(DBObject $oHostObject = null)
|
||||
{
|
||||
if (!$this->IsNullAllowed()) {
|
||||
return date($this->GetInternalFormat());
|
||||
$sDefaultValue = $this->Get('default_value');
|
||||
if (!$this->IsNullAllowed() && utils::IsNotNullOrEmptyString($sDefaultValue)) {
|
||||
try {
|
||||
$oDate = new DateTimeImmutable($sDefaultValue);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
IssueLog::Error($e->getMessage(), null, [
|
||||
'class' => get_class($this),
|
||||
'name' => $this->GetCode(),
|
||||
'stack' => $e->getTraceAsString()]);
|
||||
return $this->GetNullValue();
|
||||
}
|
||||
|
||||
return $oDate->format($this->GetInternalFormat());
|
||||
}
|
||||
return $this->GetNullValue();
|
||||
}
|
||||
|
||||
@@ -2867,6 +2867,14 @@ abstract class DBObject implements iDisplay
|
||||
protected function ListChangedValues(array $aProposal)
|
||||
{
|
||||
$aDelta = array();
|
||||
$sClass = get_class($this);
|
||||
if (MetaModel::HasLifecycle($sClass) && utils::IsNotNullOrEmptyString($this->sStimulusBeingApplied)) {
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
|
||||
if (!in_array($sStateAttCode, $aProposal)) {
|
||||
// Same state but the transition was asked, act as if the state was changed
|
||||
$aDelta[$sStateAttCode] = $this->m_aCurrValues[$sStateAttCode];
|
||||
}
|
||||
}
|
||||
foreach ($aProposal as $sAtt => $proposedValue)
|
||||
{
|
||||
if (!array_key_exists($sAtt, $this->m_aOrigValues))
|
||||
|
||||
@@ -39,7 +39,7 @@ class Event extends DBObject implements iDisplay
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>"now", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
// MetaModel::Init_AddAttribute(new AttributeString("userinfo", array("allowed_values"=>null, "sql"=>"userinfo", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
|
||||
@@ -575,6 +575,9 @@ class BinaryExpression extends Expression
|
||||
case 'LIKE':
|
||||
$sType = 'like';
|
||||
break;
|
||||
case 'IN':
|
||||
$sType = 'in';
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Operator '$sOperator' not yet supported");
|
||||
}
|
||||
@@ -641,6 +644,9 @@ class BinaryExpression extends Expression
|
||||
$sEscaped = str_replace(array('%', '_', '\\\\.*', '\\\\.'), array('.*', '.', '%', '_'), $sEscaped);
|
||||
$result = (int) preg_match("/$sEscaped/i", $mLeft);
|
||||
break;
|
||||
case 'in':
|
||||
$result = in_array($mLeft, $mRight);
|
||||
break;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
@@ -2250,7 +2256,12 @@ class ListExpression extends Expression
|
||||
*/
|
||||
public function Evaluate(array $aArgs)
|
||||
{
|
||||
throw new Exception('list expression not yet supported');
|
||||
//throw new Exception('list expression not yet supported');
|
||||
$aResult = [];
|
||||
foreach ($this->m_aExpressions as $oExpressions) {
|
||||
$aResult[] = $oExpressions->Evaluate($aArgs);
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,25 +23,23 @@
|
||||
{% set iTableCount = 0 %}
|
||||
{% if aGroupingAreasData|length > 0 %}
|
||||
{% for aAreaData in aGroupingAreasData %}
|
||||
{% if aAreaData.iItemsCount > 0 %}
|
||||
{% set iTableCount = iTableCount + 1 %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading clearfix">
|
||||
<h3 class="panel-title" style="float: left;">{{ aAreaData.sTitle }}</h3>
|
||||
{% if bCanExport %}
|
||||
<a href="{{ app.url_generator.generate('p_manage_brick_excel_export_start', {'sBrickId': sBrickId, 'sGroupingTab': sGroupingTab, 'sGroupingArea': aAreaData.sId})|raw }}"
|
||||
id="btn_export_excel_for_{{ aAreaData.sId }}"
|
||||
data-toggle="modal" data-target="#modal-for-all">
|
||||
<span class="fas fa-download fa-lg" style="float: right;"
|
||||
data-tooltip-content="{{ 'ExcelExporter:ExportMenu'|dict_s }}"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table id="table-{{ aAreaData.sId }}" class="object-list table table-striped table-bordered responsive" width="100%"></table>
|
||||
</div>
|
||||
{% set iTableCount = iTableCount + 1 %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading clearfix">
|
||||
<h3 class="panel-title" style="float: left;">{{ aAreaData.sTitle }}</h3>
|
||||
{% if bCanExport %}
|
||||
<a href="{{ app.url_generator.generate('p_manage_brick_excel_export_start', {'sBrickId': sBrickId, 'sGroupingTab': sGroupingTab, 'sGroupingArea': aAreaData.sId})|raw }}"
|
||||
id="btn_export_excel_for_{{ aAreaData.sId }}"
|
||||
data-toggle="modal" data-target="#modal-for-all">
|
||||
<span class="fas fa-download fa-lg" style="float: right;"
|
||||
data-tooltip-content="{{ 'ExcelExporter:ExportMenu'|dict_s }}"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="panel-body">
|
||||
<table id="table-{{ aAreaData.sId }}" class="object-list table table-striped table-bordered responsive" width="100%"></table>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -440,6 +440,14 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
$this->RemoveObjects($sTagClass, "SELECT $sTagClass WHERE code = '$sTagCode'");
|
||||
}
|
||||
|
||||
public function RemoveAllObjects($sClassName)
|
||||
{
|
||||
$oSet = new \DBObjectSet(new \DBObjectSearch($sClassName));
|
||||
while ($oObject = $oSet->Fetch()) {
|
||||
$oObject->DBDelete();
|
||||
}
|
||||
}
|
||||
|
||||
private function RemoveObjects($sClass, $sOQL)
|
||||
{
|
||||
$oFilter = DBSearch::FromOQL($sOQL);
|
||||
@@ -930,11 +938,12 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
*
|
||||
* @param $iExpectedCount Number of MySQL queries that should be executed
|
||||
* @param callable $oFunction Operations to perform
|
||||
* @param string $sMessage Message to display in case of failure
|
||||
*
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLQueryHasNoResultException
|
||||
*/
|
||||
protected function assertDBQueryCount($iExpectedCount, callable $oFunction)
|
||||
protected function assertDBQueryCount($iExpectedCount, callable $oFunction, $sMessage = '')
|
||||
{
|
||||
$iInitialCount = (int) CMDBSource::QueryToScalar("SHOW SESSION STATUS LIKE 'Queries'", 1);
|
||||
$oFunction();
|
||||
@@ -942,7 +951,13 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
$iCount = $iFinalCount - 1 - $iInitialCount;
|
||||
if ($iCount != $iExpectedCount)
|
||||
{
|
||||
$this->fail("Expected $iExpectedCount queries. $iCount have been executed.");
|
||||
if ($sMessage === '') {
|
||||
$sMessage = "Expected $iExpectedCount queries. $iCount have been executed.";
|
||||
}
|
||||
else {
|
||||
$sMessage .= " - Expected $iExpectedCount queries. $iCount have been executed.";
|
||||
}
|
||||
$this->fail($sMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -965,6 +980,18 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
$this->assertEquals($iExpectedCount, $iCount, "Found $iCount changes for object $sClass::$iId");
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.2.1
|
||||
*/
|
||||
protected static function assertIsDBObject(string $sExpectedClass, ?int $iExpectedKey, $oObject, ?string $sMessage = '')
|
||||
{
|
||||
self::assertNotNull($oObject, $sMessage);
|
||||
self::assertInstanceOf($sExpectedClass, $oObject, $sMessage);
|
||||
if ($iExpectedKey !== null) {
|
||||
self::assertEquals($iExpectedKey, $oObject->GetKey(), $sMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a set of XML files describing a consistent set of iTop objects
|
||||
* @param string[] $aFiles
|
||||
@@ -1464,4 +1491,28 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$this->assertEquals(1, $oSet->Count(), $sMessage);
|
||||
}
|
||||
|
||||
static protected function StartStopwatchInThePast(DBObject $oObject, string $sStopwatchAttCode, int $iDelayInSecond)
|
||||
{
|
||||
$iStartDate = time() - $iDelayInSecond;
|
||||
/** @var \ormStopWatch $oStopwatch */
|
||||
$oStopwatch = $oObject->Get($sStopwatchAttCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObject), $sStopwatchAttCode);
|
||||
$oStopwatch->Start($oObject, $oAttDef, $iStartDate);
|
||||
$oStopwatch->ComputeDeadlines($oObject, $oAttDef);
|
||||
$oObject->Set($sStopwatchAttCode, $oStopwatch);
|
||||
}
|
||||
|
||||
|
||||
static protected function StopStopwatchInTheFuture(DBObject $oObject, string $sStopwatchAttCode, int $iDelayInSecond)
|
||||
{
|
||||
$iEndDate = time() + $iDelayInSecond;
|
||||
/** @var \ormStopWatch $oStopwatch */
|
||||
$oStopwatch = $oObject->Get($sStopwatchAttCode);
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObject), $sStopwatchAttCode);
|
||||
$oStopwatch->Stop($oObject, $oAttDef, $iEndDate);
|
||||
$oStopwatch->ComputeDeadlines($oObject, $oAttDef);
|
||||
$oObject->Set($sStopwatchAttCode, $oStopwatch);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ namespace Combodo\iTop\Test\UnitTest;
|
||||
use CMDBSource;
|
||||
use DeprecatedCallsLog;
|
||||
use MySQLTransactionNotClosedException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use ReflectionMethod;
|
||||
use SetupUtils;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use const DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
|
||||
@@ -23,7 +23,7 @@ use const DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
*
|
||||
* @since 3.0.4 3.1.1 3.2.0 N°6658 move some setUp/tearDown code to the corresponding methods *BeforeClass to speed up tests process time.
|
||||
*/
|
||||
abstract class ItopTestCase extends KernelTestCase
|
||||
abstract class ItopTestCase extends TestCase
|
||||
{
|
||||
public const TEST_LOG_DIR = 'test';
|
||||
|
||||
|
||||
@@ -20,16 +20,6 @@ class MenuNodeTest extends ItopDataTestCase {
|
||||
$this->oUR = $this->CreateUserRequest(666, $aUserRequestCustomParams);
|
||||
}
|
||||
|
||||
private function StartStopwatchInThePast(\UserRequest $oTicket, string $sAttCode, int $iSecDelay)
|
||||
{
|
||||
$iStartDate = time() - $iSecDelay;
|
||||
/** @var \ormStopWatch $oStopwatch */
|
||||
$oStopwatch = $oTicket->Get($sAttCode);
|
||||
$oAttDef = \MetaModel::GetAttributeDef(get_class($oTicket), $sAttCode);
|
||||
$oStopwatch->Start($oTicket, $oAttDef, $iStartDate);
|
||||
$oStopwatch->ComputeDeadlines($oTicket, $oAttDef);
|
||||
$oTicket->Set($sAttCode, $oStopwatch);
|
||||
}
|
||||
|
||||
public function RenderOQLSearchProvider()
|
||||
{
|
||||
@@ -70,7 +60,7 @@ OQL;
|
||||
*/
|
||||
public function testRenderOQLSearchOqlWithDateFormatOnDeadline()
|
||||
{
|
||||
$this->StartStopwatchInThePast($this->oUR, 'ttr', 10);
|
||||
static::StartStopwatchInThePast($this->oUR, 'ttr', 10);
|
||||
|
||||
$sOql = <<<OQL
|
||||
SELECT `UserRequest` FROM UserRequest AS `UserRequest` WHERE (DATE_FORMAT(`UserRequest`.`ttr_escalation_deadline`, '%Y%v') != DATE_FORMAT(NOW(), '%Y%v'))
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use AttributeDate;
|
||||
use AttributeDateTime;
|
||||
use Change;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use MetaModel;
|
||||
@@ -229,7 +231,7 @@ PHP
|
||||
$this->assertEquals($bComputationExpected, $oAttDef->HasPHPComputation(), "Standard DataModel should be configured with property 'has_php_computation'=$sComputationExpected for $sClass:$sAttCode");
|
||||
}
|
||||
|
||||
public function WithConstraintParameterProvider()
|
||||
public static function WithConstraintParameterProvider()
|
||||
{
|
||||
return [
|
||||
['User', 'profile_list', true, true],
|
||||
@@ -238,4 +240,109 @@ PHP
|
||||
['Ticket', 'functionalcis_list', false, true],
|
||||
];
|
||||
}
|
||||
|
||||
public function testDateTimeEmptyDefaultReturnsNullAsDefaultValue()
|
||||
{
|
||||
// Given
|
||||
$oDateAttribute = new AttributeDateTime('start_date', ['sql' => 'start_date', 'is_null_allowed' => false, 'default_value' => '', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]);
|
||||
$oDateAttribute->SetHostClass('WorkOrder');
|
||||
$oWorkOrder = MetaModel::NewObject('WorkOrder');
|
||||
|
||||
//When
|
||||
$defaultValue = $oDateAttribute->GetDefaultValue();
|
||||
$oField = $oDateAttribute->MakeFormField($oWorkOrder);
|
||||
|
||||
// Then
|
||||
self::assertNull($defaultValue, 'Empty default value for DateTime attribute should give null default value');
|
||||
self::assertEmpty($oField->GetCurrentValue(), 'Empty default value for DateTime attribute should give empty form field');
|
||||
}
|
||||
|
||||
public function testDateEmptyDefaultReturnsNullAsDefaultValue()
|
||||
{
|
||||
// Given
|
||||
$oDateAttribute = new AttributeDate('start_date', ['sql' => 'start_date', 'is_null_allowed' => false, 'default_value' => '', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]);
|
||||
$oDateAttribute->SetHostClass('WorkOrder');
|
||||
$oWorkOrder = MetaModel::NewObject('WorkOrder');
|
||||
|
||||
//When
|
||||
$defaultValue = $oDateAttribute->GetDefaultValue();
|
||||
$oField = $oDateAttribute->MakeFormField($oWorkOrder);
|
||||
|
||||
// Then
|
||||
self::assertNull($defaultValue, 'Empty default value for Date attribute should give null default value');
|
||||
self::assertEmpty($oField->GetCurrentValue(), 'Empty default value for DateTime attribute should give empty form field');
|
||||
}
|
||||
|
||||
|
||||
public function testDateTimeNowAsDefaultGivesCurrentDateAsDefaultValue()
|
||||
{
|
||||
// Given
|
||||
$oDateAttribute = new AttributeDateTime('start_date', ['sql' => 'start_date', 'is_null_allowed' => false, 'default_value' => 'now', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]);
|
||||
$oDateAttribute->SetHostClass('WorkOrder');
|
||||
$oWorkOrder = MetaModel::NewObject('WorkOrder');
|
||||
|
||||
//When
|
||||
$defaultValue = $oDateAttribute->GetDefaultValue();
|
||||
$oField = $oDateAttribute->MakeFormField($oWorkOrder);
|
||||
|
||||
// Then
|
||||
$sNow = date($oDateAttribute->GetInternalFormat());
|
||||
self::assertEquals($sNow, $defaultValue, 'Now as default value for DateTime attribute should give current date as default value');
|
||||
self::assertEquals($sNow, $oField->GetCurrentValue(), 'Now as default value for DateTime attribute should give current date as form field');
|
||||
}
|
||||
|
||||
|
||||
public function testDateNowAsDefaultGivesCurrentDateAsDefaultValue()
|
||||
{
|
||||
// Given
|
||||
$oDateAttribute = new AttributeDate('start_date', ['sql' => 'start_date', 'is_null_allowed' => false, 'default_value' => 'now', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]);
|
||||
$oDateAttribute->SetHostClass('WorkOrder');
|
||||
$oWorkOrder = MetaModel::NewObject('WorkOrder');
|
||||
|
||||
//When
|
||||
$defaultValue = $oDateAttribute->GetDefaultValue();
|
||||
$oField = $oDateAttribute->MakeFormField($oWorkOrder);
|
||||
|
||||
// Then
|
||||
$sNow = date($oDateAttribute->GetInternalFormat());
|
||||
self::assertEquals($sNow, $defaultValue, 'Now as default value for Date attribute should give current date as default value');
|
||||
self::assertEquals($sNow, $oField->GetCurrentValue(), 'Now as default value for Date attribute should give current date as form field');
|
||||
}
|
||||
|
||||
public function testDateTimeIntervalAsDefaultGivesCorrectDateAsDefaultValue()
|
||||
{
|
||||
// Given
|
||||
$oDateAttribute = new AttributeDateTime('start_date', ['sql' => 'start_date', 'is_null_allowed' => false, 'default_value' => '+1day', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]);
|
||||
$oDateAttribute->SetHostClass('WorkOrder');
|
||||
$oWorkOrder = MetaModel::NewObject('WorkOrder');
|
||||
|
||||
//When
|
||||
$defaultValue = $oDateAttribute->GetDefaultValue();
|
||||
$oField = $oDateAttribute->MakeFormField($oWorkOrder);
|
||||
|
||||
// Then
|
||||
$oDate = new \DateTimeImmutable('+1day');
|
||||
$sExpected = $oDate->format($oDateAttribute->GetInternalFormat());
|
||||
self::assertEquals($sExpected, $defaultValue, 'Interval as default value for DateTime attribute should give correct date as default value');
|
||||
self::assertEquals($sExpected, $oField->GetCurrentValue(), 'Interval as default value for DateTime attribute should give correct date as form field');
|
||||
}
|
||||
|
||||
public function testDateIntervalAsDefaultGivesCorrectDateAsDefaultValue()
|
||||
{
|
||||
// Given
|
||||
$oDateAttribute = new AttributeDate('start_date', ['sql' => 'start_date', 'is_null_allowed' => false, 'default_value' => '+1day', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]);
|
||||
$oDateAttribute->SetHostClass('WorkOrder');
|
||||
$oWorkOrder = MetaModel::NewObject('WorkOrder');
|
||||
|
||||
//When
|
||||
$defaultValue = $oDateAttribute->GetDefaultValue();
|
||||
$oField = $oDateAttribute->MakeFormField($oWorkOrder);
|
||||
|
||||
// Then
|
||||
$oDate = new \DateTimeImmutable('+1day');
|
||||
$sExpected = $oDate->format($oDateAttribute->GetInternalFormat());
|
||||
self::assertEquals($sExpected, $defaultValue, 'Interval as default value for Date attribute should give correct date as default value');
|
||||
self::assertEquals($sExpected, $oField->GetCurrentValue(), 'Interval as default value for Date attribute should give correct date as form field');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -62,7 +62,7 @@ class EventIssueTest extends ItopDataTestCase
|
||||
$oEventIssue->DBInsert();
|
||||
}
|
||||
catch (CoreException $e) {
|
||||
$this->fail('we should be able to persist the object though it contains long values in its attributes');
|
||||
$this->fail('we should be able to persist the object though it contains long values in its attributes: '.$e->getMessage());
|
||||
}
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
{
|
||||
$aExpressions = array(
|
||||
// Test case to isolate for troubleshooting purposes
|
||||
array('1+1', 2),
|
||||
array("'a' IN ('a', 'b')", true),
|
||||
);
|
||||
}
|
||||
else
|
||||
@@ -141,6 +141,9 @@ class ExpressionEvaluateTest extends ItopDataTestCase
|
||||
array('"2020-06-12 17:35:13" < "2020-06-12"', 0),
|
||||
array('"2020-06-12 00:00:00" = "2020-06-12"', 0),
|
||||
|
||||
// IN operator
|
||||
array("'a' IN ('a', 'b')", true),
|
||||
|
||||
// Logical operators
|
||||
array('0 AND 0', 0),
|
||||
array('1 AND 0', 0),
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use MetaModel;
|
||||
use Person;
|
||||
|
||||
class TriggerOnStateEnterTest extends ItopDataTestCase
|
||||
{
|
||||
const CREATE_TEST_ORG = true;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->RemoveAllObjects(\Trigger::class);
|
||||
$this->RemoveAllObjects(\EventNotificationEmail::class);
|
||||
}
|
||||
|
||||
public function testIsTriggeredOnTransition()
|
||||
{
|
||||
$iTrigger = $this->GivenTriggerWithAction('TriggerOnStateEnter', 'assigned');
|
||||
$oUserRequest = $this->GivenUserRequest('new');
|
||||
|
||||
$oUserRequest->ApplyStimulus('ev_assign');
|
||||
$this->AssertTriggerExecuted($iTrigger, 1, 'The trigger should have been executed');
|
||||
|
||||
$oUserRequest->ApplyStimulus('ev_assign');
|
||||
$this->AssertTriggerExecuted($iTrigger, 1, 'The trigger should not be executed when stimulus not expected in current state');
|
||||
}
|
||||
|
||||
public function testIsTriggeredOnTransitionStayingInSameState()
|
||||
{
|
||||
$iTrigger = $this->GivenTriggerWithAction('TriggerOnStateEnter', 'assigned');
|
||||
$oUserRequest = $this->GivenUserRequest('new');
|
||||
$oUserRequest->ApplyStimulus('ev_assign');
|
||||
|
||||
$bTransitioned = $oUserRequest->ApplyStimulus('ev_reassign');
|
||||
$this->assertTrue($bTransitioned, 'The stimulus should have been accepted');
|
||||
|
||||
$this->AssertTriggerExecuted($iTrigger, 2, 'The trigger should have been executed twice');
|
||||
}
|
||||
public function testIsTriggeredOnNewObject()
|
||||
{
|
||||
$iTrigger = $this->GivenTriggerWithAction('TriggerOnStateEnter', 'new');
|
||||
$oUserRequest = $this->GivenUserRequest('new');
|
||||
$this->AssertTriggerExecuted($iTrigger, 0, 'The trigger TriggerOnStateEnter should not be executed on created object');
|
||||
}
|
||||
|
||||
private function GivenTriggerWithAction(string $sTriggerClass, string $sState)
|
||||
{
|
||||
$iTrigger = $this->GivenObjectInDB($sTriggerClass, [
|
||||
'description' => 'Description',
|
||||
'target_class' => 'UserRequest',
|
||||
'state' => $sState,
|
||||
]);
|
||||
$this->GivenObjectInDB('ActionEmail', [
|
||||
'from' => 'test@combodo.com',
|
||||
'subject' => 'Subject',
|
||||
'body' => 'Body',
|
||||
'description' => 'Description',
|
||||
'test_recipient' => 'test@combodo.com',
|
||||
'name' => 'UserRequest',
|
||||
'asynchronous' => 'yes',
|
||||
'trigger_list' => [
|
||||
"trigger_id:$iTrigger",
|
||||
],
|
||||
]);
|
||||
return $iTrigger;
|
||||
}
|
||||
|
||||
private function AssertTriggerExecuted(int $iTrigger, $iCount, $sMessage = '')
|
||||
{
|
||||
$oSearch = new \DBObjectSearch('EventNotificationEmail');
|
||||
$oSearch->AddCondition('trigger_id', $iTrigger);
|
||||
$oSet = new \DBObjectSet($oSearch);
|
||||
$this->assertEquals($iCount, $oSet->Count(), $sMessage);
|
||||
}
|
||||
|
||||
public function GivenUserRequest(string $sStatus): ?\DBObject
|
||||
{
|
||||
$iUserRequest = $this->GivenObjectInDB('UserRequest', [
|
||||
'title' => 'Title',
|
||||
'description' => 'Description',
|
||||
'status' => $sStatus,
|
||||
]);
|
||||
return MetaModel::GetObject('UserRequest', $iUserRequest);
|
||||
}
|
||||
}
|
||||
@@ -491,52 +491,65 @@ class UserRightsTest extends ItopDataTestCase
|
||||
|
||||
public function testFindUser_ExistingInternalUser()
|
||||
{
|
||||
$sLogin = 'UserRightsFindUser'.uniqid();
|
||||
$iKey = $this->CreateUser($sLogin, self::$aURP_Profiles['Administrator'])->GetKey();
|
||||
$oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]);
|
||||
$sLogin = 'AnInternalUser'.uniqid();
|
||||
$iKey = $this->GivenObjectInDB(\UserLocal::class, ['login' => $sLogin]);
|
||||
|
||||
$this->assertNotNull($oUser);
|
||||
$this->assertEquals($iKey, $oUser->GetKey());
|
||||
$this->assertEquals(\UserLocal::class, get_class($oUser));
|
||||
$this->assertDBQueryCount(
|
||||
1,
|
||||
fn() => $this->FindUserAndAssertItHasBeenFound($sLogin, $iKey),
|
||||
'A query should be performed the first time FindUser is called'
|
||||
);
|
||||
|
||||
$this->assertDBQueryCount(0, function() use ($sLogin, $iKey){
|
||||
$oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]);
|
||||
static::assertEquals($iKey, $oUser->GetKey());
|
||||
static::assertEquals(\UserLocal::class, get_class($oUser));
|
||||
});
|
||||
$this->assertDBQueryCount(
|
||||
0,
|
||||
fn() => $this->FindUserAndAssertItHasBeenFound($sLogin, $iKey),
|
||||
'The cache should prevent additional queries on subsequent calls'
|
||||
);
|
||||
}
|
||||
|
||||
public function testFindUser_ExistingExternalUser()
|
||||
{
|
||||
$sLogin = 'UserRightsFindUser'.uniqid();
|
||||
$sLogin = 'AnExternalUser'.uniqid();
|
||||
$iKey = $this->GivenObjectInDB(\UserExternal::class, ['login' => $sLogin]);
|
||||
|
||||
$iKey = $this->GivenObjectInDB(\UserExternal::class, [
|
||||
'login' => $sLogin,
|
||||
'language' => 'EN US',
|
||||
]);
|
||||
$this->assertDBQueryCount(
|
||||
2,
|
||||
fn() => $this->FindUserAndAssertItHasBeenFound($sLogin, $iKey),
|
||||
'Some queries should be performed the first time FindUser is called'
|
||||
);
|
||||
|
||||
$oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]);
|
||||
|
||||
$this->assertNotNull($oUser);
|
||||
$this->assertEquals($iKey, $oUser->GetKey());
|
||||
$this->assertEquals(\UserExternal::class, get_class($oUser));
|
||||
|
||||
$this->assertDBQueryCount(0, function() use ($sLogin, $iKey){
|
||||
$oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]);
|
||||
static::assertEquals($iKey, $oUser->GetKey());
|
||||
static::assertEquals(\UserExternal::class, get_class($oUser));
|
||||
});
|
||||
$this->assertDBQueryCount(
|
||||
0,
|
||||
fn() => $this->FindUserAndAssertItHasBeenFound($sLogin, $iKey),
|
||||
'The cache should prevent additional queries on subsequent calls'
|
||||
);
|
||||
}
|
||||
|
||||
public function testFindUser_UnknownLogin_AvoidSameSqlQueryTwice()
|
||||
public function testFindUser_UnknownLogin()
|
||||
{
|
||||
$sLogin = 'UserRightsFindUser'.uniqid();
|
||||
$oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]);
|
||||
$this->assertNull($oUser);
|
||||
$sLogin = 'NobodyLogin';
|
||||
|
||||
$this->assertDBQueryCount(0, function() use ($sLogin){
|
||||
$oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]);
|
||||
$this->assertNull($oUser);
|
||||
});
|
||||
$this->assertDBQueryCount(
|
||||
2,
|
||||
fn() => $this->FindUserAndAssertItWasNotFound($sLogin),
|
||||
'Some queries should be performed the first time FindUser is called'
|
||||
);
|
||||
|
||||
$this->assertDBQueryCount(
|
||||
0,
|
||||
fn() => $this->FindUserAndAssertItWasNotFound($sLogin),
|
||||
'The cache should prevent additional queries on subsequent calls'
|
||||
);
|
||||
}
|
||||
|
||||
public function FindUserAndAssertItHasBeenFound($sLogin, $iExpectedKey)
|
||||
{
|
||||
$oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]);
|
||||
static::assertIsDBObject(\User::class, $iExpectedKey, $oUser, 'FindUser should return the User object corresponding to the login');
|
||||
}
|
||||
public function FindUserAndAssertItWasNotFound($sLogin)
|
||||
{
|
||||
$oUser = $this->InvokeNonPublicStaticMethod(UserRights::class, "FindUser", [$sLogin]);
|
||||
static::assertNull($oUser, 'FindUser should return null when the login is unknown');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user