mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-23 17:22:18 +02:00
Merge branch 'support/3.1.0' into feature/5324-powerportaluser-repairprofiles
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class ApplicationObjectExtensionTest extends \Combodo\iTop\Test\UnitTest\ItopDataTestCase
|
||||
{
|
||||
const CREATE_TEST_ORG = true;
|
||||
|
||||
// Count the calls by name
|
||||
private static array $aCalls = [];
|
||||
private static int $iCalls = 0;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->RequireOnceUnitTestFile('iApplicationObjectExtension/MockApplicationObjectExtensionForTest1.php');
|
||||
$this->ResetApplicationObjectExtensions();
|
||||
// Count all the calls to this object
|
||||
MockApplicationObjectExtensionForTest1::SetCallBack([ApplicationObjectExtensionTest::class, 'IncrementCallCount']);
|
||||
}
|
||||
|
||||
public function tearDown(): void
|
||||
{
|
||||
MockApplicationObjectExtensionForTest1::SetModifications('Person', 'name', 0);
|
||||
MockApplicationObjectExtensionForTest1::SetCallBack(null);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public static function IncrementCallCount(string $sOrigin)
|
||||
{
|
||||
self::$aCalls[$sOrigin] = (self::$aCalls[$sOrigin] ?? 0) + 1;
|
||||
self::$iCalls++;
|
||||
}
|
||||
|
||||
public static function ResetCallCount()
|
||||
{
|
||||
self::$aCalls = [];
|
||||
self::$iCalls = 0;
|
||||
}
|
||||
|
||||
public function testExtensionCalled()
|
||||
{
|
||||
// Check that extension is called
|
||||
$oPerson = $this->CreatePerson(1);
|
||||
$oPerson->Set('first_name', 'testUpdateReentranceProtection');
|
||||
MockApplicationObjectExtensionForTest1::SetModifications('Person', 'name', 1);
|
||||
self::ResetCallCount();
|
||||
$oPerson->DBUpdate();
|
||||
// Called twice, the first call will provoke the DBUpdate and call again the object extension
|
||||
$this->assertEquals(2, self::$iCalls);
|
||||
}
|
||||
|
||||
public function testUpdateReentranceProtection()
|
||||
{
|
||||
$oPerson = $this->CreatePerson(1);
|
||||
|
||||
// Check that loop limit is 10
|
||||
$i = 15;
|
||||
self::ResetCallCount();
|
||||
MockApplicationObjectExtensionForTest1::SetModifications('Person', 'name', $i);
|
||||
$oPerson->Set('first_name', 'testUpdateReentranceProtection');
|
||||
$oPerson->DBUpdate();
|
||||
$this->assertEquals(10, self::$iCalls);
|
||||
}
|
||||
|
||||
public function testModificationsOnUpdate()
|
||||
{
|
||||
$oPerson = $this->CreatePerson(1);
|
||||
$oPerson->Set('first_name', 'testUpdateReentranceProtection');
|
||||
|
||||
self::ResetCallCount();
|
||||
MockApplicationObjectExtensionForTest1::SetModifications('Person', 'name', 1);
|
||||
$oPerson->DBUpdate();
|
||||
$this->assertEquals(2, self::$iCalls);
|
||||
}
|
||||
|
||||
public function testModificationsOnInsert()
|
||||
{
|
||||
self::ResetCallCount();
|
||||
MockApplicationObjectExtensionForTest1::SetModifications('Person', 'name', 1);
|
||||
$oPerson = $this->CreatePerson(1);
|
||||
$this->assertEquals(2, self::$iCalls);
|
||||
}
|
||||
|
||||
|
||||
public function testModificationsOnInsertWith2Extensions()
|
||||
{
|
||||
self::ResetCallCount();
|
||||
$this->RequireOnceUnitTestFile('iApplicationObjectExtension/MockApplicationObjectExtensionForTest2.php');
|
||||
$this->ResetApplicationObjectExtensions();
|
||||
// Count all the calls to this object
|
||||
MockApplicationObjectExtensionForTest2::SetCallBack([ApplicationObjectExtensionTest::class, 'IncrementCallCount']);
|
||||
|
||||
MockApplicationObjectExtensionForTest1::SetModifications('Person', 'name', 2);
|
||||
MockApplicationObjectExtensionForTest2::SetModifications('Person', 'first_name', 2);
|
||||
$oPerson = $this->CreatePerson(1);
|
||||
$this->assertEquals(6, self::$iCalls);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2018 Dennis Lassiter
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Application;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use DesignerXMLField;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* @covers DesignerFormField
|
||||
*/
|
||||
class DesignerFormFieldTest extends ItopTestCase
|
||||
{
|
||||
/**
|
||||
* @param string $sFieldFQCN
|
||||
* @param string $sInputValue
|
||||
* @param string $sExpectedValue
|
||||
*
|
||||
* @return void
|
||||
* @throws \ReflectionException
|
||||
* @covers DesignerLongTextField::PrepareValueForRendering
|
||||
* @dataProvider PrepareValueForRenderingProvider
|
||||
*/
|
||||
public function testPrepareValueForRendering(string $sFieldFQCN, string $sInputValue, string $sExpectedValue)
|
||||
{
|
||||
$oField = new $sFieldFQCN('field_code', 'Field label', $sInputValue);
|
||||
|
||||
$sTestedValue = $this->InvokeNonPublicMethod($sFieldFQCN, 'PrepareValueForRendering', $oField, []);
|
||||
$this->assertEquals($sExpectedValue, $sTestedValue);
|
||||
}
|
||||
|
||||
public function PrepareValueForRenderingProvider(): array
|
||||
{
|
||||
return [
|
||||
'DesignerLongTextField should not double encode XML' => [
|
||||
'\\DesignerLongTextField',
|
||||
<<<XML
|
||||
<root>
|
||||
<title id="title">Foo & Bar</title>
|
||||
</root>
|
||||
XML,
|
||||
<<<HTML
|
||||
<root>
|
||||
<title id="title">Foo & Bar</title>
|
||||
</root>
|
||||
HTML
|
||||
],
|
||||
'DesignerXMLField should double encode XML' => [
|
||||
'\\DesignerXMLField',
|
||||
<<<XML
|
||||
<root>
|
||||
<title id="title">Foo & Bar</title>
|
||||
</root>
|
||||
XML,
|
||||
<<<HTML
|
||||
<root>
|
||||
<title id="title">Foo &amp; Bar</title>
|
||||
</root>
|
||||
HTML
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test object for AbstractApplicationObjectExtension API
|
||||
*/
|
||||
class MockApplicationObjectExtensionForTest1 extends AbstractApplicationObjectExtension
|
||||
{
|
||||
protected static $iCountModify;
|
||||
protected static $sClass;
|
||||
protected static $sAttCodeToModify;
|
||||
protected static $callBack;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function SetCallBack($callBack)
|
||||
{
|
||||
static::$callBack = $callBack;
|
||||
}
|
||||
|
||||
public static function SetModifications($sClass, $sAttCodeToModify, $iCountModify)
|
||||
{
|
||||
static::$sClass = $sClass;
|
||||
static::$sAttCodeToModify = $sAttCodeToModify;
|
||||
if (!MetaModel::IsValidClass($sClass) || !MetaModel::IsValidAttCode($sClass, $sAttCodeToModify)) {
|
||||
throw new Exception("Invalid class $sClass or attcode $sAttCodeToModify");
|
||||
}
|
||||
static::$iCountModify = $iCountModify;
|
||||
}
|
||||
|
||||
public function OnDBUpdate($oObject, $oChange = null)
|
||||
{
|
||||
if (get_class($oObject) !== static::$sClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_null(static::$callBack)) {
|
||||
call_user_func(static::$callBack, 'OnDBUpdate');
|
||||
}
|
||||
|
||||
$aPreviousValues = $oObject->ListPreviousValuesForUpdatedAttributes();
|
||||
$sPreviousValues = print_r($aPreviousValues, true);
|
||||
|
||||
IssueLog::Info(__METHOD__." received previous values:\n$sPreviousValues");
|
||||
|
||||
if (static::$iCountModify > 0) {
|
||||
static::$iCountModify--;
|
||||
$oObject->Set(static::$sAttCodeToModify, 'Value_'.rand());
|
||||
$oObject->DBUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public function OnDBInsert($oObject, $oChange = null)
|
||||
{
|
||||
if (get_class($oObject) !== static::$sClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_null(static::$callBack)) {
|
||||
call_user_func(static::$callBack, 'OnDBInsert');
|
||||
}
|
||||
|
||||
if (static::$iCountModify > 0) {
|
||||
static::$iCountModify--;
|
||||
$oObject->Set(static::$sAttCodeToModify, 'Value_'.rand());
|
||||
$oObject->DBUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Test object for AbstractApplicationObjectExtension API
|
||||
*/
|
||||
class MockApplicationObjectExtensionForTest2 extends AbstractApplicationObjectExtension
|
||||
{
|
||||
protected static $iCountModify;
|
||||
protected static $sClass;
|
||||
protected static $sAttCodeToModify;
|
||||
protected static $callBack;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function SetCallBack($callBack)
|
||||
{
|
||||
static::$callBack = $callBack;
|
||||
}
|
||||
|
||||
public static function SetModifications($sClass, $sAttCodeToModify, $iCountModify)
|
||||
{
|
||||
static::$sClass = $sClass;
|
||||
static::$sAttCodeToModify = $sAttCodeToModify;
|
||||
if (!MetaModel::IsValidClass($sClass) || !MetaModel::IsValidAttCode($sClass, $sAttCodeToModify)) {
|
||||
throw new Exception("Invalid class $sClass or attcode $sAttCodeToModify");
|
||||
}
|
||||
static::$iCountModify = $iCountModify;
|
||||
}
|
||||
|
||||
public function OnDBUpdate($oObject, $oChange = null)
|
||||
{
|
||||
if (get_class($oObject) !== static::$sClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_null(static::$callBack)) {
|
||||
call_user_func(static::$callBack, 'OnDBUpdate');
|
||||
}
|
||||
|
||||
$aPreviousValues = $oObject->ListPreviousValuesForUpdatedAttributes();
|
||||
$sPreviousValues = print_r($aPreviousValues, true);
|
||||
|
||||
IssueLog::Info(__METHOD__." received previous values:\n$sPreviousValues");
|
||||
|
||||
if (static::$iCountModify > 0) {
|
||||
static::$iCountModify--;
|
||||
$oObject->Set(static::$sAttCodeToModify, 'Value_'.rand());
|
||||
$oObject->DBUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
public function OnDBInsert($oObject, $oChange = null)
|
||||
{
|
||||
if (get_class($oObject) !== static::$sClass) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_null(static::$callBack)) {
|
||||
call_user_func(static::$callBack, 'OnDBInsert');
|
||||
}
|
||||
|
||||
if (static::$iCountModify > 0) {
|
||||
static::$iCountModify--;
|
||||
$oObject->Set(static::$sAttCodeToModify, 'Value_'.rand());
|
||||
$oObject->DBUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -841,17 +841,19 @@ class utilsTest extends ItopTestCase
|
||||
*
|
||||
* @dataProvider escapeHtmlProvider
|
||||
*/
|
||||
public function testEscapeHtml($sInput, $sExpectedEscaped)
|
||||
public function testEscapeHtml($sInput, $sExpectedEscaped, $bDoubleEncode = false)
|
||||
{
|
||||
if (is_null($sExpectedEscaped)) {
|
||||
$sExpectedEscaped = $sInput;
|
||||
}
|
||||
|
||||
$sEscaped = utils::EscapeHtml($sInput);
|
||||
$sEscaped = utils::EscapeHtml($sInput, $bDoubleEncode);
|
||||
self::assertSame($sExpectedEscaped, $sEscaped);
|
||||
|
||||
$sEscapedDecoded = utils::EscapedHtmlDecode($sEscaped);
|
||||
self::assertSame($sInput, $sEscapedDecoded);
|
||||
if (false === $bDoubleEncode) {
|
||||
self::assertSame($sInput, $sEscapedDecoded);
|
||||
}
|
||||
}
|
||||
|
||||
public function escapeHtmlProvider()
|
||||
@@ -859,8 +861,17 @@ class utilsTest extends ItopTestCase
|
||||
return [
|
||||
'no escape' => ['abcdefghijklmnop', null],
|
||||
'&' => ['abcdefghijklmnop&0123456789', 'abcdefghijklmnop&0123456789'],
|
||||
['"double quotes"', '"double quotes"'],
|
||||
["'simple quotes'", ''simple quotes''],
|
||||
'double quotes' => ['"double quotes"', '"double quotes"'],
|
||||
'simple quotes' => ["'simple quotes'", ''simple quotes''],
|
||||
'no double encode' => [
|
||||
'<root><title>Foo & Bar</title></root>',
|
||||
'<root><title>Foo & Bar</title></root>'
|
||||
],
|
||||
'double encode forced (for XML mostly)' => [
|
||||
'<root><title>Foo & Bar</title></root>',
|
||||
'<root><title>Foo &amp; Bar</title></root>',
|
||||
true
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,4 +181,17 @@ PHP
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function testMakeFormField(): void
|
||||
{
|
||||
$oPerson = $this->CreatePerson(1);
|
||||
$oPerson->Set('email', 'toto@tutu.com');
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oPerson), 'email');
|
||||
$oFormFieldWithTouchedAtt = $oAttDef->MakeFormField($oPerson);
|
||||
$this->assertFalse($oFormFieldWithTouchedAtt->IsValidationDisabled(), 'email is part of modified fields, we must have field validation');
|
||||
|
||||
$oPerson->DBUpdate(); // reset list of changed attributes
|
||||
$oFormFieldNoTouchedAtt = $oAttDef->MakeFormField($oPerson);
|
||||
$this->assertTrue($oFormFieldNoTouchedAtt->IsValidationDisabled(), 'email wasn\'t modified, we must not validate the corresponding field');
|
||||
}
|
||||
}
|
||||
@@ -284,8 +284,6 @@ class CRUDEventTest extends ItopDataTestCase
|
||||
*/
|
||||
public function testInfiniteUpdateDoneLoop()
|
||||
{
|
||||
$this->markTestSkipped('TEST Skipped: Protection not working.');
|
||||
|
||||
$oPerson = $this->CreatePerson(1);
|
||||
$this->assertIsObject($oPerson);
|
||||
|
||||
@@ -343,7 +341,8 @@ class CRUDEventTest extends ItopDataTestCase
|
||||
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_CHECK_TO_WRITE]);
|
||||
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_BEFORE_WRITE]);
|
||||
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_AFTER_WRITE]);
|
||||
$this->assertEquals(16, self::$iEventCalls);
|
||||
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_LINKS_CHANGED]);
|
||||
$this->assertEquals(20, self::$iEventCalls);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -391,7 +390,8 @@ class CRUDEventTest extends ItopDataTestCase
|
||||
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_CHECK_TO_WRITE]);
|
||||
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_BEFORE_WRITE]);
|
||||
$this->assertEquals(4, self::$aEventCalls[EVENT_DB_AFTER_WRITE]);
|
||||
$this->assertEquals(16, self::$iEventCalls);
|
||||
$this->assertEquals(3, self::$aEventCalls[EVENT_DB_LINKS_CHANGED]);
|
||||
$this->assertEquals(19, self::$iEventCalls);
|
||||
|
||||
// Read the object explicitly from the DB to check that the role has been set
|
||||
$oSet = new DBObjectSet(DBSearch::FromOQL('SELECT Team WHERE id=:id'), [], ['id' => $oTeam->GetKey()]);
|
||||
@@ -480,9 +480,52 @@ class CRUDEventTest extends ItopDataTestCase
|
||||
$this->assertTrue(CRUDEventReceiver::$bIsObjectInCrudStack);
|
||||
}
|
||||
|
||||
public function testLinksAdded()
|
||||
{
|
||||
// Create a Person
|
||||
$oPerson = $this->CreatePerson(1);
|
||||
|
||||
// Create a Team
|
||||
$oTeam = MetaModel::NewObject(Team::class, ['name' => 'TestTeamWithLinkToAPerson', 'org_id' => $this->getTestOrgId()]);
|
||||
$oTeam->DBInsert();
|
||||
|
||||
// Start receiving events
|
||||
$oEventReceiver = new CRUDEventReceiver();
|
||||
$oEventReceiver->RegisterCRUDListeners();
|
||||
|
||||
// Create a link between Person and Team => generate 2 EVENT_DB_LINKS_CHANGED
|
||||
$oLnk = MetaModel::NewObject(lnkPersonToTeam::class, ['person_id' => $oPerson->GetKey(), 'team_id' => $oTeam->GetKey()]);
|
||||
$oLnk->DBInsert();
|
||||
|
||||
$this->assertEquals(2, self::$aEventCalls[EVENT_DB_LINKS_CHANGED]);
|
||||
}
|
||||
|
||||
public function testLinksDeleted()
|
||||
{
|
||||
// Create a Person
|
||||
$oPerson = $this->CreatePerson(1);
|
||||
|
||||
// Create a Team
|
||||
$oTeam = MetaModel::NewObject(Team::class, ['name' => 'TestTeamWithLinkToAPerson', 'org_id' => $this->getTestOrgId()]);
|
||||
$oTeam->DBInsert();
|
||||
|
||||
// Create a link between Person and Team => generate 2 EVENT_DB_LINKS_CHANGED
|
||||
$oLnk = MetaModel::NewObject(lnkPersonToTeam::class, ['person_id' => $oPerson->GetKey(), 'team_id' => $oTeam->GetKey()]);
|
||||
$oLnk->DBInsert();
|
||||
|
||||
// Start receiving events
|
||||
$oEventReceiver = new CRUDEventReceiver();
|
||||
$oEventReceiver->RegisterCRUDListeners();
|
||||
|
||||
$oLnk->DBDelete();
|
||||
|
||||
$this->assertEquals(2, self::$aEventCalls[EVENT_DB_LINKS_CHANGED]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add debug feature to test support class
|
||||
*/
|
||||
class ClassesWithDebug
|
||||
{
|
||||
/**
|
||||
@@ -505,7 +548,7 @@ class ClassesWithDebug
|
||||
}
|
||||
|
||||
/**
|
||||
* Count events received
|
||||
* Test support class used to count events received
|
||||
* And allow callbacks on events
|
||||
*/
|
||||
class CRUDEventReceiver extends ClassesWithDebug
|
||||
@@ -514,6 +557,18 @@ class CRUDEventReceiver extends ClassesWithDebug
|
||||
|
||||
public static $bIsObjectInCrudStack;
|
||||
|
||||
//
|
||||
|
||||
/**
|
||||
* Add a specific callback for an event
|
||||
*
|
||||
* @param string $sEvent event name
|
||||
* @param string $sClass event source class name
|
||||
* @param string $sFct function to call on CRUDEventReceiver object
|
||||
* @param int $iCount limit the number of calls to the callback
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function AddCallback(string $sEvent, string $sClass, string $sFct, int $iCount = 1): void
|
||||
{
|
||||
$this->aCallbacks[$sEvent][$sClass] = [
|
||||
@@ -527,7 +582,15 @@ class CRUDEventReceiver extends ClassesWithDebug
|
||||
$this->aCallbacks = [];
|
||||
}
|
||||
|
||||
// Event callbacks
|
||||
|
||||
/**
|
||||
* Event callbacks => this function counts the received events by event name and source class
|
||||
* If AddCallback() method has been called a specific callback is called, else only the count is done
|
||||
*
|
||||
* @param \Combodo\iTop\Service\Events\EventData $oData
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function OnEvent(EventData $oData)
|
||||
{
|
||||
$sEvent = $oData->GetEvent();
|
||||
@@ -556,6 +619,7 @@ class CRUDEventReceiver extends ClassesWithDebug
|
||||
EventService::RegisterListener(EVENT_DB_BEFORE_WRITE, [$this, 'OnEvent']);
|
||||
EventService::RegisterListener(EVENT_DB_AFTER_WRITE, [$this, 'OnEvent']);
|
||||
EventService::RegisterListener(EVENT_DB_AFTER_DELETE, [$this, 'OnEvent']);
|
||||
EventService::RegisterListener(EVENT_DB_LINKS_CHANGED, [$this, 'OnEvent']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -116,13 +116,13 @@ class DBObjectTest extends ItopDataTestCase
|
||||
$oOrg->DBUpdate();
|
||||
|
||||
$this->assertCount(0, $oOrg->ListChanges());
|
||||
$this->assertCount(0, $oOrg->ListPreviousValuesForUpdatedAttributes());
|
||||
$this->assertCount(1, $oOrg->ListPreviousValuesForUpdatedAttributes());
|
||||
|
||||
$oOrg->Set('name', $oOrg->Get('name'));
|
||||
$this->assertCount(0, $oOrg->ListChanges());
|
||||
$oOrg->DBUpdate();
|
||||
$this->assertCount(0, $oOrg->ListChanges());
|
||||
$this->assertCount(0, $oOrg->ListPreviousValuesForUpdatedAttributes());
|
||||
$this->assertCount(1, $oOrg->ListPreviousValuesForUpdatedAttributes());
|
||||
|
||||
$oOrg->DBDelete();
|
||||
|
||||
@@ -132,7 +132,7 @@ class DBObjectTest extends ItopDataTestCase
|
||||
$oOrg->Set('code', strtoupper('testListPreviousValuesForUpdatedAttributes'));
|
||||
$oOrg->DBUpdate();
|
||||
$oOrg->DBUpdate();
|
||||
$this->assertCount(0, $oOrg->ListPreviousValuesForUpdatedAttributes());
|
||||
$this->assertCount(1, $oOrg->ListPreviousValuesForUpdatedAttributes());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,7 +140,7 @@ class DBObjectTest extends ItopDataTestCase
|
||||
* @covers DBObject::Get
|
||||
* @covers DBObject::Set
|
||||
*/
|
||||
public function testAttributeRefresh_FriendlyName()
|
||||
public function testAttributeRefresh_FriendlyNameWithoutCascade()
|
||||
{
|
||||
$oObject = \MetaModel::NewObject('Person', array('name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2));
|
||||
|
||||
@@ -149,6 +149,21 @@ class DBObjectTest extends ItopDataTestCase
|
||||
static::assertEquals('John Who', $oObject->Get('friendlyname'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers DBObject::NewObject
|
||||
* @covers DBObject::Get
|
||||
* @covers DBObject::Set
|
||||
*/
|
||||
public function testAttributeRefresh_FriendlyNameWithCascade()
|
||||
{
|
||||
$oServer = \MetaModel::NewObject('Server', ['name' => 'ServerTest', 'org_id' => 3]);
|
||||
$oServer->DBInsert();
|
||||
$oDBServer = \MetaModel::NewObject('DBServer', ['name' => 'DBServerTest', 'org_id' => 3, 'system_id' => $oServer]);
|
||||
|
||||
static::assertEquals('ServerTest', $oDBServer->Get('system_name'));
|
||||
static::assertEquals('DBServerTest ServerTest', $oDBServer->Get('friendlyname'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers MetaModel::GetObject
|
||||
* @covers DBObject::Get
|
||||
@@ -174,8 +189,7 @@ class DBObjectTest extends ItopDataTestCase
|
||||
public function testPartialAttributeEvaluation()
|
||||
{
|
||||
$oObject = \MetaModel::NewObject('Person', array('name' => 'Foo', 'org_id' => 3, 'location_id' => 2));
|
||||
|
||||
static::assertEquals('', $oObject->Get('friendlyname'));
|
||||
static::assertEquals(' Foo', $oObject->Get('friendlyname'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +200,7 @@ class DBObjectTest extends ItopDataTestCase
|
||||
{
|
||||
$oObject = \MetaModel::NewObject('Person', array('org_id' => 3, 'location_id' => 2));
|
||||
|
||||
static::assertEquals('', $oObject->Get('friendlyname'));
|
||||
static::assertEquals(' ', $oObject->Get('friendlyname'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,7 +212,7 @@ class DBObjectTest extends ItopDataTestCase
|
||||
$oUserProfile = new \URP_UserProfile();
|
||||
$oUserProfile->Set('profileid', 2);
|
||||
|
||||
static::assertEquals('', $oUserProfile->Get('friendlyname'));
|
||||
static::assertEquals('Link between and Portal user', $oUserProfile->Get('friendlyname'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +220,7 @@ class DBObjectTest extends ItopDataTestCase
|
||||
* @covers DBObject::Get
|
||||
* @covers DBObject::Set
|
||||
*/
|
||||
public function testAttributeRefresh_ObsolescenceFlag()
|
||||
public function testAttributeRefresh_ObsolescenceFlagWithoutCascade()
|
||||
{
|
||||
$oObject = \MetaModel::NewObject('Person', array('name' => 'Foo', 'first_name' => 'John', 'org_id' => 3, 'location_id' => 2));
|
||||
|
||||
@@ -215,6 +229,24 @@ class DBObjectTest extends ItopDataTestCase
|
||||
static::assertEquals(true, (bool)$oObject->Get('obsolescence_flag'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers DBObject::NewObject
|
||||
* @covers DBObject::Get
|
||||
* @covers DBObject::Set
|
||||
*/
|
||||
public function testAttributeRefresh_ObsolescenceFlagWithCascade()
|
||||
{
|
||||
$this->markTestSkipped('Postponed');
|
||||
// Necessary ext. key for $oDBServer
|
||||
$oServer = \MetaModel::NewObject('Server', ['name' => 'ServerTest', 'org_id' => 3]);
|
||||
$oServer->DBInsert();
|
||||
$oDBServer = \MetaModel::NewObject('DBServer', ['name' => 'DBServerTest', 'org_id' => 3, 'system_id' => $oServer, 'status' => 'inactive']);
|
||||
$oDBServer->DBInsert();
|
||||
|
||||
$oDBSchema = \MetaModel::NewObject('DatabaseSchema', ['name' => 'DBSchemaTest', 'org_id' => 3, 'dbserver_id' => $oDBServer]);
|
||||
static::assertEquals(true, $oDBSchema->Get('obsolescence_flag'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers DBObject::NewObject
|
||||
* @covers DBObject::Get
|
||||
@@ -520,7 +552,8 @@ class DBObjectTest extends ItopDataTestCase
|
||||
$oPerson = $this->CreatePersonInstance();
|
||||
|
||||
// Insert without Reload
|
||||
$oPerson->DBInsert();
|
||||
$key = $oPerson->DBInsert();
|
||||
$this->assertSame($key, $oPerson->GetKey());
|
||||
|
||||
// Get initial values
|
||||
$aValues1 = [];
|
||||
@@ -539,6 +572,9 @@ class DBObjectTest extends ItopDataTestCase
|
||||
|
||||
// 1st Reload
|
||||
$oPerson->Reload(true);
|
||||
// N°6281 - Rest API core/create key value is no more between quote
|
||||
$this->assertSame($key, $oPerson->GetKey());
|
||||
|
||||
$sPerson2 = print_r($oPerson, true);
|
||||
$this->assertNotEquals($sPerson1, $sPerson2);
|
||||
|
||||
|
||||
@@ -319,7 +319,7 @@ class ExpressionEvaluateTest extends iTopDataTestCase
|
||||
['URP_UserProfile', ['profileid' => 2], 'friendlyname', ''],
|
||||
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'name', 'Grenoble'],
|
||||
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'friendlyname', ''],
|
||||
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'org_name', ''],
|
||||
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'org_name', 'IT Department'],
|
||||
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'org_id_friendlyname', ''],
|
||||
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'org_id', 2],
|
||||
['Location', ['name' => 'Grenoble', 'org_id' => 2], 'CONCAT(SUBSTR(name, 4), " cause")', 'noble cause'],
|
||||
|
||||
@@ -1,66 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.1">
|
||||
<classes>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeNone">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>none</edit_mode>
|
||||
<relation_type>link</relation_type>
|
||||
<read_only>true</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeAddOnly">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>add_only</edit_mode>
|
||||
<relation_type>link</relation_type>
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeAddRemove">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>add_remove</edit_mode>
|
||||
<relation_type>link</relation_type>
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeActions">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>actions</edit_mode>
|
||||
<relation_type>link</relation_type>
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeInPlace">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>in_place</edit_mode>
|
||||
<relation_type>property</relation_type>
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetNoEditMode">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<linked_class>Ticket</linked_class>
|
||||
<relation_type>link</relation_type>
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetIndirect">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSetIndirect">
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
</classes>
|
||||
</itop_design>
|
||||
|
||||
@@ -1,52 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
|
||||
<classes>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeNone">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>none</edit_mode>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeAddOnly">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>add_only</edit_mode>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeAddRemove">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>add_remove</edit_mode>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeActions">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>actions</edit_mode>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeInPlace">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>in_place</edit_mode>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetNoEditMode">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<linked_class>Ticket</linked_class>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetIndirect">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSetIndirect"/>
|
||||
</fields>
|
||||
</class>
|
||||
</classes>
|
||||
</itop_design>
|
||||
|
||||
@@ -4,53 +4,6 @@
|
||||
<class id="ClassWithCustomZlist">
|
||||
<presentation/>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeNone">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>none</edit_mode>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeAddOnly">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>add_only</edit_mode>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeAddRemove">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>add_remove</edit_mode>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeActions">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>actions</edit_mode>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeInPlace">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>in_place</edit_mode>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetNoEditMode">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<linked_class>Ticket</linked_class>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetIndirect">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSetIndirect"/>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetDisplayStyle">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet"/>
|
||||
|
||||
@@ -14,67 +14,6 @@
|
||||
</custom_presentations>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeNone">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>none</edit_mode>
|
||||
<relation_type>link</relation_type>
|
||||
<read_only>true</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeAddOnly">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>add_only</edit_mode>
|
||||
<relation_type>link</relation_type>
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeAddRemove">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>add_remove</edit_mode>
|
||||
<relation_type>link</relation_type>
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeActions">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>actions</edit_mode>
|
||||
<relation_type>link</relation_type>
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetEditModeInPlace">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<edit_mode>in_place</edit_mode>
|
||||
<relation_type>property</relation_type>
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetNoEditMode">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
<linked_class>Ticket</linked_class>
|
||||
<relation_type>link</relation_type>
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetIndirect">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSetIndirect">
|
||||
<read_only>false</read_only>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="ClassWithAttributeLinkedSetDisplayStyle">
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeLinkedSet">
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Sources\Form\Field;
|
||||
|
||||
use Combodo\iTop\Form\Field\StringField;
|
||||
use Combodo\iTop\Form\Field\SubFormField;
|
||||
use Combodo\iTop\Form\Validator\CustomRegexpValidator;
|
||||
use Combodo\iTop\Form\Validator\IntegerValidator;
|
||||
use Combodo\iTop\Form\Validator\MandatoryValidator;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
class FieldTest extends ItopTestCase
|
||||
{
|
||||
public function testIsValidationDisabled(): void
|
||||
{
|
||||
$oField = new StringField('test');
|
||||
$oField->SetCurrentValue('toto@johny.invalid');
|
||||
$sDumbEmailValidatorErrorMessage = 'dumb email validator error message';
|
||||
$oDumbEmailValidator = new CustomRegexpValidator('\d+@\d+\.\d{2,3}', $sDumbEmailValidatorErrorMessage);
|
||||
$oField->AddValidator($oDumbEmailValidator);
|
||||
|
||||
$bIsFieldValid = $oField->Validate();
|
||||
$this->assertFalse($bIsFieldValid);
|
||||
$this->assertCount(1, $oField->GetErrorMessages());
|
||||
$this->assertSame($sDumbEmailValidatorErrorMessage, $oField->GetErrorMessages()[0]);
|
||||
|
||||
/** @noinspection PhpRedundantOptionalArgumentInspection */
|
||||
$oField->SetValidationDisabled(true);
|
||||
$this->assertTrue($oField->Validate());
|
||||
}
|
||||
|
||||
public function testSetMandatory(): void
|
||||
{
|
||||
$oField = new StringField('test');
|
||||
$this->assertCount(0, $oField->GetValidators());
|
||||
|
||||
$oField->SetMandatory(true);
|
||||
$aValidatorsAfterSetMandatoryTrue = $oField->GetValidators();
|
||||
$this->assertCount(1, $aValidatorsAfterSetMandatoryTrue);
|
||||
$this->assertIsObject($aValidatorsAfterSetMandatoryTrue[0]);
|
||||
$this->assertSame(MandatoryValidator::class, get_class($aValidatorsAfterSetMandatoryTrue[0]));
|
||||
|
||||
$oField->SetMandatory(false);
|
||||
$this->assertCount(0, $oField->GetValidators());
|
||||
}
|
||||
|
||||
public function testAddValidator(): void
|
||||
{
|
||||
$oField = new StringField('test');
|
||||
$this->assertCount(0, $oField->GetValidators());
|
||||
|
||||
$oField->SetCurrentValue('not a numeric value');
|
||||
$this->assertTrue($oField->Validate());
|
||||
|
||||
$oField->AddValidator(new IntegerValidator());
|
||||
$aValidatorsAfterAddingIntegerValidator = $oField->GetValidators();
|
||||
$this->assertCount(1, $aValidatorsAfterAddingIntegerValidator);
|
||||
$this->assertIsObject($aValidatorsAfterAddingIntegerValidator[0]);
|
||||
$this->assertSame(IntegerValidator::class, get_class($aValidatorsAfterAddingIntegerValidator[0]));
|
||||
$this->assertFalse($oField->Validate());
|
||||
$this->assertCount(1, $oField->GetErrorMessages());
|
||||
}
|
||||
|
||||
public function testValidateWithTwoValidatorsFirstWrong(): void
|
||||
{
|
||||
$oField = new StringField('test');
|
||||
$oField->SetCurrentValue('string with spaces');
|
||||
|
||||
$sFirstValidatorInvalidResultErrorMsg = 'dumb email validator error message';
|
||||
$oFirstValidatorInvalidResult = new CustomRegexpValidator('^[a-z]+$', $sFirstValidatorInvalidResultErrorMsg);
|
||||
$oField->AddValidator($oFirstValidatorInvalidResult);
|
||||
|
||||
$oSecondValidatorValidResult = new CustomRegexpValidator('^.+$', 'valid');
|
||||
$oField->AddValidator($oSecondValidatorValidResult);
|
||||
|
||||
$this->assertFalse($oField->Validate());
|
||||
$this->assertCount(1, $oField->GetErrorMessages());
|
||||
$this->assertSame($sFirstValidatorInvalidResultErrorMsg, $oField->GetErrorMessages()[0]);
|
||||
}
|
||||
|
||||
public function testSubFormFieldValidation(): void
|
||||
{
|
||||
$oSubFormField = new SubFormField('test_subformfield');
|
||||
|
||||
$oField = new StringField('test_field');
|
||||
$oField->SetMandatory(true);
|
||||
|
||||
$oSubFormField->GetForm()->AddField($oField);
|
||||
|
||||
$bIsSubFormFieldValid = $oSubFormField->Validate();
|
||||
$this->assertFalse($bIsSubFormFieldValid);
|
||||
$this->assertCount(1, $oSubFormField->GetErrorMessages());
|
||||
|
||||
$oField->SetCurrentValue('test string');
|
||||
$bIsSubFormFieldValidAfterFieldUpdate = $oSubFormField->Validate();
|
||||
$this->assertTrue($bIsSubFormFieldValidAfterFieldUpdate);
|
||||
$this->assertCount(0, $oSubFormField->GetErrorMessages());
|
||||
}
|
||||
|
||||
public function testRemoveValidatorsOfClass(): void {
|
||||
$oField = new StringField('test');
|
||||
|
||||
$this->assertCount(0, $oField->GetValidators());
|
||||
$oField->RemoveValidatorsOfClass(CustomRegexpValidator::class);
|
||||
$this->assertCount(0, $oField->GetValidators());
|
||||
|
||||
$oField->AddValidator(new IntegerValidator());
|
||||
$this->assertCount(1, $oField->GetValidators());
|
||||
$oField->RemoveValidatorsOfClass(CustomRegexpValidator::class);
|
||||
$this->assertCount(1, $oField->GetValidators());
|
||||
|
||||
$oField->AddValidator(new CustomRegexpValidator('^.*$'));
|
||||
$this->assertCount(2, $oField->GetValidators());
|
||||
$oField->RemoveValidatorsOfClass(CustomRegexpValidator::class);
|
||||
$this->assertCount(1, $oField->GetValidators());
|
||||
|
||||
$oField->AddValidator(new CustomRegexpValidator('^.*$'));
|
||||
$oField->AddValidator(new CustomRegexpValidator('^.*$'));
|
||||
$this->assertCount(3, $oField->GetValidators());
|
||||
$oField->RemoveValidatorsOfClass(CustomRegexpValidator::class);
|
||||
$this->assertCount(1, $oField->GetValidators());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Form;
|
||||
|
||||
use Combodo\iTop\Form\Field\LinkedSetField;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use ormLinkSet;
|
||||
use Person;
|
||||
|
||||
class LinkedSetFieldTest extends ItopDataTestCase {
|
||||
public function testValidate(): void {
|
||||
$sLinkedClass = Ticket::class;
|
||||
$oLinkedSetField = new LinkedSetField('test');
|
||||
$oLinkedSetField->SetIndirect(false);
|
||||
$oLinkedSetField->SetTargetClass($sLinkedClass);
|
||||
$oLinkedSetField->SetLinkedClass($sLinkedClass);
|
||||
$oLinkedSetField->SetLnkAttributesToDisplay(['title' => 'title']);
|
||||
|
||||
$oSetThreeExistingTickets = new ormLinkSet(Person::class, 'tickets_list');
|
||||
$this->CreateTestOrganization();
|
||||
$oUserRequest1 = $this->CreateUserRequest(1);
|
||||
$oUserRequest2 = $this->CreateUserRequest(2);
|
||||
$oUserRequest3 = $this->CreateUserRequest(3);
|
||||
$oSetThreeExistingTickets->AddItem($oUserRequest1);
|
||||
$oSetThreeExistingTickets->AddItem($oUserRequest2);
|
||||
$oSetThreeExistingTickets->AddItem($oUserRequest3);
|
||||
$oLinkedSetField->SetCurrentValue($oSetThreeExistingTickets);
|
||||
$this->assertTrue($oLinkedSetField->Validate(), 'A set with existing objects and no modifications must be OK');
|
||||
|
||||
$oUserRequest1->Set('title', 'this a modified title !');
|
||||
$this->assertTrue($oLinkedSetField->Validate(), 'A set with existing objects and a valid modification must be OK');
|
||||
|
||||
$oUserRequest1->Set('title', '');
|
||||
$this->assertFalse($oLinkedSetField->Validate(), 'A set with existing objects and an invalid modification must be KO');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Form;
|
||||
|
||||
use Combodo\iTop\Form\Field\MultipleChoicesField;
|
||||
use Combodo\iTop\Form\Field\MultipleSelectField;
|
||||
use Combodo\iTop\Form\Field\SelectField;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
use ContextTag;
|
||||
|
||||
class MultipleChoicesFieldTest extends ItopTestCase
|
||||
{
|
||||
public function testValidateForMultipleSelectField(): void
|
||||
{
|
||||
$oMultipleChoicesField = new MultipleSelectField('test');
|
||||
$oMultipleChoicesField->AddChoice('A');
|
||||
$oMultipleChoicesField->AddChoice('B');
|
||||
$oMultipleChoicesField->AddChoice('C');
|
||||
$oMultipleChoicesField->AddChoice('D');
|
||||
|
||||
// N°1150 the control was added for the REST API initially and was only triggered with the corresponding ContextTag
|
||||
$oRestContext = new ContextTag(ContextTag::TAG_REST);
|
||||
$this->ValidateMultipleSelectField($oMultipleChoicesField);
|
||||
|
||||
// retrying without REST context
|
||||
unset($oRestContext);
|
||||
$this->ValidateMultipleSelectField($oMultipleChoicesField);
|
||||
}
|
||||
|
||||
private function ValidateMultipleSelectField(MultipleChoicesField $oMultipleChoicesField): void
|
||||
{
|
||||
$oMultipleChoicesField->SetCurrentValue(null);
|
||||
$this->assertTrue($oMultipleChoicesField->Validate(), 'No value must be valid');
|
||||
|
||||
$sExistingValue = 'A';
|
||||
$sNonExistingValue = 'Non existing choice';
|
||||
$sNonExistingValue1 = 'Non existing choice 1';
|
||||
$sNonExistingValue2 = 'Non existing choice 2';
|
||||
|
||||
$oMultipleChoicesField->SetCurrentValue($sExistingValue);
|
||||
$this->assertTrue($oMultipleChoicesField->Validate(), 'Value among possible ones is valid');
|
||||
|
||||
$oMultipleChoicesField->SetCurrentValue($sNonExistingValue);
|
||||
$this->assertFalse($oMultipleChoicesField->Validate(), 'Value not among possible ones is invalid');
|
||||
$this->assertCount(1, $oMultipleChoicesField->GetErrorMessages());
|
||||
$this->assertStringContainsString($sNonExistingValue, $oMultipleChoicesField->GetErrorMessages()[0]);
|
||||
|
||||
$oMultipleChoicesField->SetCurrentValue([$sNonExistingValue1, $sNonExistingValue2]);
|
||||
$this->assertFalse($oMultipleChoicesField->Validate(), 'Multiple values not among possible ones is invalid');
|
||||
$this->assertCount(2, $oMultipleChoicesField->GetErrorMessages());
|
||||
$this->assertStringContainsString($sNonExistingValue1, $oMultipleChoicesField->GetErrorMessages()[0]);
|
||||
$this->assertStringContainsString($sNonExistingValue2, $oMultipleChoicesField->GetErrorMessages()[1]);
|
||||
|
||||
$oMultipleChoicesField->SetCurrentValue([$sExistingValue, $sNonExistingValue]);
|
||||
$this->assertFalse($oMultipleChoicesField->Validate(), 'Valid value + Value not among possible ones is invalid');
|
||||
$this->assertCount(1, $oMultipleChoicesField->GetErrorMessages());
|
||||
$this->assertStringContainsString($sNonExistingValue, $oMultipleChoicesField->GetErrorMessages()[0]);
|
||||
|
||||
$oMultipleChoicesField->SetCurrentValue([$sExistingValue, $sNonExistingValue1, $sNonExistingValue2]);
|
||||
$this->assertFalse($oMultipleChoicesField->Validate(), 'Valid value + Multiple values not among possible ones is invalid');
|
||||
$this->assertCount(2, $oMultipleChoicesField->GetErrorMessages());
|
||||
$this->assertStringContainsString($sNonExistingValue1, $oMultipleChoicesField->GetErrorMessages()[0]);
|
||||
$this->assertStringContainsString($sNonExistingValue2, $oMultipleChoicesField->GetErrorMessages()[1]);
|
||||
}
|
||||
|
||||
public function testValidateForSelectField(): void
|
||||
{
|
||||
$oMultipleChoicesField = new SelectField('test');
|
||||
$oMultipleChoicesField->AddChoice('A');
|
||||
$oMultipleChoicesField->AddChoice('B');
|
||||
$oMultipleChoicesField->AddChoice('C');
|
||||
$oMultipleChoicesField->AddChoice('D');
|
||||
|
||||
// N°1150 the control was added for the REST API initially and was only triggered with the corresponding ContextTag
|
||||
$oRestContext = new ContextTag(ContextTag::TAG_REST);
|
||||
$this->ValidateSelectField($oMultipleChoicesField);
|
||||
|
||||
// retrying without REST context
|
||||
unset($oRestContext);
|
||||
$this->ValidateSelectField($oMultipleChoicesField);
|
||||
|
||||
$oMultipleChoicesField = new SelectField('test');
|
||||
$oMultipleChoicesField->SetChoices(['A' => 'A', 'B' => 'B', 'C' => 'C', 'D' => 'D']);
|
||||
$this->ValidateSelectField($oMultipleChoicesField);
|
||||
}
|
||||
|
||||
private function ValidateSelectField(MultipleChoicesField $oMultipleChoicesField): void
|
||||
{
|
||||
$oMultipleChoicesField->SetCurrentValue(null);
|
||||
$this->assertTrue($oMultipleChoicesField->Validate(), 'No value must be valid');
|
||||
|
||||
$sExistingValue = 'A';
|
||||
$sNonExistingValue = 'Non existing choice';
|
||||
|
||||
$oMultipleChoicesField->SetCurrentValue($sExistingValue);
|
||||
$this->assertTrue($oMultipleChoicesField->Validate(), 'Value among possible ones is valid');
|
||||
|
||||
$oMultipleChoicesField->SetCurrentValue($sNonExistingValue);
|
||||
$this->assertFalse($oMultipleChoicesField->Validate(), 'Value not among possible ones is invalid');
|
||||
$this->assertCount(1, $oMultipleChoicesField->GetErrorMessages());
|
||||
$this->assertStringContainsString($sNonExistingValue, $oMultipleChoicesField->GetErrorMessages()[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Form;
|
||||
|
||||
use Combodo\iTop\Form\Field\SelectObjectField;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use ContextTag;
|
||||
use DBObjectSearch;
|
||||
use Organization;
|
||||
|
||||
class SelectObjectFieldTest extends ItopDataTestCase {
|
||||
public function testValidate(): void {
|
||||
$oSelectObjectField = new SelectObjectField('test');
|
||||
$oSelectObjectField->SetSearch(DBObjectSearch::FromOQL('SELECT '.Organization::class));
|
||||
|
||||
// N°1150 the control was added for the REST API initially and was only triggered with the corresponding ContextTag
|
||||
$oRestContext = new ContextTag(ContextTag::TAG_REST);
|
||||
$this->ValidateSelectObjectField($oSelectObjectField);
|
||||
|
||||
// retrying without REST context
|
||||
unset($oRestContext);
|
||||
$this->ValidateSelectObjectField($oSelectObjectField);
|
||||
}
|
||||
|
||||
private function ValidateSelectObjectField(SelectObjectField $oSelectObjectField): void {
|
||||
$oSelectObjectField->SetCurrentValue(null);
|
||||
$this->assertTrue($oSelectObjectField->Validate(), 'No value must be valid');
|
||||
|
||||
$sExistingOrganizationId = 1;
|
||||
$oSelectObjectField->SetCurrentValue($sExistingOrganizationId);
|
||||
$this->assertTrue($oSelectObjectField->Validate(), 'An existing object id must be valid');
|
||||
|
||||
$sNonExistingOrganizationId = 999999;
|
||||
$oSelectObjectField->SetCurrentValue($sNonExistingOrganizationId);
|
||||
$this->assertFalse($oSelectObjectField->Validate(), 'An non existing object id must be invalid');
|
||||
$this->assertCount(1, $oSelectObjectField->GetErrorMessages());
|
||||
$this->assertStringContainsString($sNonExistingOrganizationId, $oSelectObjectField->GetErrorMessages()[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Sources\Form\Validator;
|
||||
|
||||
use Combodo\iTop\Form\Field\StringField;
|
||||
use Combodo\iTop\Form\Validator\MandatoryValidator;
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
class ValidatorTest extends ItopTestCase
|
||||
{
|
||||
public function testMandatoryValidator()
|
||||
{
|
||||
$oField = new StringField('test');
|
||||
$oField->SetMandatory(true);
|
||||
$oField->SetCurrentValue('there is a value !');
|
||||
|
||||
$bIsMandatoryFieldValidWithExistingValue = $oField->Validate();
|
||||
$this->assertTrue($bIsMandatoryFieldValidWithExistingValue);
|
||||
|
||||
$oField->SetCurrentValue(null);
|
||||
$bIsMandatoryFieldValidWithNoValue = $oField->Validate();
|
||||
$this->assertFalse($bIsMandatoryFieldValidWithNoValue);
|
||||
$this->assertNotEmpty($oField->GetErrorMessages());
|
||||
$this->assertCount(1, $oField->GetErrorMessages());
|
||||
$this->assertStringContainsString(MandatoryValidator::DEFAULT_ERROR_MESSAGE, $oField->GetErrorMessages()[0]);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,16 @@ use utils;
|
||||
*/
|
||||
class RouterTest extends ItopTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->RequireOnceItopFile('setup/setuputils.class.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Combodo\iTop\Service\Router\Router::GenerateUrl
|
||||
* @dataProvider GenerateUrlProvider
|
||||
@@ -169,6 +179,94 @@ class RouterTest extends ItopTestCase
|
||||
$this->assertEquals($bShouldBePresent, $bIsPresent, "Route '$sRoute' was not expected amongst the available routes.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Combodo\iTop\Service\Router\Router::GetRoutes
|
||||
* @return void
|
||||
*
|
||||
* @since N°6618 Covers that the cache isn't re-generated at each call of the GetRoutes method
|
||||
*/
|
||||
public function testGetRoutesCacheGeneratedOnlyOnce(): void
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$sRoutesCacheFilePath = $this->InvokeNonPublicMethod(Router::class, 'GetCacheFileAbsPath', $oRouter, []);
|
||||
|
||||
// Developer mode must be disabled for the routes cache to be used
|
||||
$oConf = utils::GetConfig();
|
||||
$mDeveloperModePreviousValue = $oConf->Get('developer_mode.enabled');
|
||||
$oConf->Set('developer_mode.enabled', false);
|
||||
|
||||
// Generate cache for first time
|
||||
$this->InvokeNonPublicMethod(Router::class, 'GetRoutes', $oRouter, []);
|
||||
|
||||
// Check that file exists and retrieve modification timestamp
|
||||
if (false === is_file($sRoutesCacheFilePath)) {
|
||||
$this->fail("Cache file was not generated ($sRoutesCacheFilePath)");
|
||||
}
|
||||
|
||||
clearstatcache();
|
||||
$iFirstModificationTimestamp = filemtime($sRoutesCacheFilePath);
|
||||
$this->debug("Initial timestamp: $iFirstModificationTimestamp");
|
||||
|
||||
// Wait for just 1s to ensure timestamps would be different is the file is re-generated
|
||||
sleep(1);
|
||||
|
||||
// Call GetRoutes() again to see if cache gets re-generated or not
|
||||
$this->InvokeNonPublicMethod(Router::class, 'GetRoutes', $oRouter, []);
|
||||
|
||||
// Check that file still exists and that modification timestamp has not changed
|
||||
if (false === is_file($sRoutesCacheFilePath)) {
|
||||
$this->fail("Cache file is no longer present, that should not happen! ($sRoutesCacheFilePath)");
|
||||
}
|
||||
|
||||
clearstatcache();
|
||||
$iSecondModificationTimestamp = filemtime($sRoutesCacheFilePath);
|
||||
$this->debug("Second timestamp: $iSecondModificationTimestamp");
|
||||
|
||||
$this->assertSame($iFirstModificationTimestamp, $iSecondModificationTimestamp, "Cache file timestamp changed, seems like cache is not working and was re-generated when it should not!");
|
||||
|
||||
// Restore previous value for following tests
|
||||
$oConf->Set('developer_mode.enabled', $mDeveloperModePreviousValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Combodo\iTop\Service\Router\Router::GetRoutes
|
||||
* @return void
|
||||
*
|
||||
* @since N°6618 Covers that the cache is re-generated correctly if corrupted
|
||||
*/
|
||||
public function testGetRoutesCacheRegeneratedCorrectlyIfCorrupted(): void
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$sRoutesCacheFilePath = $this->InvokeNonPublicMethod(Router::class, 'GetCacheFileAbsPath', $oRouter, []);
|
||||
|
||||
// Developer mode must be disabled for the routes cache to be used
|
||||
$oConf = utils::GetConfig();
|
||||
$mDeveloperModePreviousValue = $oConf->Get('developer_mode.enabled');
|
||||
$oConf->Set('developer_mode.enabled', false);
|
||||
|
||||
// Generate corrupted cache manually
|
||||
$sFaultyStatement = 'return 1;';
|
||||
file_put_contents($sRoutesCacheFilePath, <<<PHP
|
||||
<?php
|
||||
|
||||
{$sFaultyStatement}
|
||||
PHP
|
||||
);
|
||||
|
||||
// Retrieve routes to access / fix cache in the process
|
||||
$aRoutes = $this->InvokeNonPublicMethod(Router::class, 'GetRoutes', $oRouter, []);
|
||||
|
||||
// Check that routes are an array
|
||||
$this->assertTrue(is_array($aRoutes));
|
||||
|
||||
// Check that file content doesn't contain `return 1`
|
||||
clearstatcache();
|
||||
$this->assertStringNotContainsString($sFaultyStatement, file_get_contents($sRoutesCacheFilePath), "Cache file still contains the faulty statement ($sFaultyStatement)");
|
||||
|
||||
// Restore previous value for following tests
|
||||
$oConf->Set('developer_mode.enabled', $mDeveloperModePreviousValue);
|
||||
}
|
||||
|
||||
public function GetRoutesProvider(): array
|
||||
{
|
||||
return [
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Service\TemporaryObjects;
|
||||
|
||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectConfig;
|
||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectHelper;
|
||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectManager;
|
||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectRepository;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class TemporaryObjectManagerTest extends ItopDataTestCase
|
||||
{
|
||||
const USE_TRANSACTION = true;
|
||||
const CREATE_TEST_ORG = false;
|
||||
|
||||
private TemporaryObjectConfig $oConfig;
|
||||
private $oManager;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->oConfig = TemporaryObjectConfig::GetInstance();
|
||||
$this->oManager = TemporaryObjectManager::GetInstance();
|
||||
}
|
||||
|
||||
public function testCreateTemporaryObject()
|
||||
{
|
||||
$sTempId = 'testCreateTemporaryObject';
|
||||
$this->oConfig->SetConfigTemporaryLifetime(3000);
|
||||
$this->oConfig->SetConfigTemporaryForce(true);
|
||||
|
||||
$oDescriptor = $this->oManager->CreateTemporaryObject($sTempId, 'FakedClass', -1, TemporaryObjectHelper::OPERATION_CREATE);
|
||||
|
||||
$this->assertNull( $oDescriptor);
|
||||
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$oDescriptor = $this->CreateTemporaryObject($sTempId, $oOrg, 3000, TemporaryObjectHelper::OPERATION_CREATE);
|
||||
|
||||
$this->assertNotNull( $oDescriptor);
|
||||
}
|
||||
|
||||
public function testCancelAllTemporaryObjects()
|
||||
{
|
||||
$sTempId = 'testCancelAllTemporaryObjects';
|
||||
$oRepository = TemporaryObjectRepository::GetInstance();
|
||||
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, 3000, TemporaryObjectHelper::OPERATION_CREATE);
|
||||
$this->assertEquals(1, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
|
||||
$this->oManager->CancelAllTemporaryObjects($sTempId);
|
||||
$this->assertEquals(0, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, 3000, TemporaryObjectHelper::OPERATION_CREATE);
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, 3000, TemporaryObjectHelper::OPERATION_CREATE);
|
||||
$this->assertEquals(2, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
|
||||
$this->oManager->CancelAllTemporaryObjects($sTempId);
|
||||
$this->assertEquals(0, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
}
|
||||
|
||||
public function testExtendTemporaryObjectsLifetime()
|
||||
{
|
||||
$sTempId = 'testExtendTemporaryObjectsLifetime';
|
||||
$oRepository = TemporaryObjectRepository::GetInstance();
|
||||
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, -1, TemporaryObjectHelper::OPERATION_CREATE);
|
||||
$this->assertEquals(1, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
$this->assertEquals(1, $oRepository->SearchByExpired()->Count());
|
||||
|
||||
$this->oConfig->SetConfigTemporaryLifetime(3000);
|
||||
$this->oManager->ExtendTemporaryObjectsLifetime($sTempId);
|
||||
$this->assertEquals(0, $oRepository->SearchByExpired()->Count());
|
||||
}
|
||||
|
||||
public function testGarbageExpiredTemporaryObjects()
|
||||
{
|
||||
$sTempId = 'testGarbageExpiredTemporaryObjects';
|
||||
$oRepository = TemporaryObjectRepository::GetInstance();
|
||||
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, -1, TemporaryObjectHelper::OPERATION_CREATE);
|
||||
$this->assertEquals(1, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
$this->assertEquals(1, $oRepository->SearchByExpired()->Count());
|
||||
|
||||
$this->oManager->GarbageExpiredTemporaryObjects();
|
||||
$this->assertEquals(0, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, -1, TemporaryObjectHelper::OPERATION_CREATE);
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, -1, TemporaryObjectHelper::OPERATION_CREATE);
|
||||
$this->assertEquals(2, $oRepository->SearchByExpired()->Count());
|
||||
|
||||
$this->oManager->GarbageExpiredTemporaryObjects();
|
||||
$this->assertEquals(0, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
|
||||
$this->oManager->GarbageExpiredTemporaryObjects();
|
||||
$this->assertEquals(0, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
}
|
||||
|
||||
public function testHandleCreatedTemporaryObjects()
|
||||
{
|
||||
$sTempId = 'testHandleTemporaryObjects';
|
||||
$oRepository = TemporaryObjectRepository::GetInstance();
|
||||
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$oOrgTemp = $this->CreateTestOrganization();
|
||||
$oOrg->Set('parent_id', $oOrgTemp->GetKey());
|
||||
$oOrg->DBUpdate();
|
||||
|
||||
$aContext = ['create' => ['transaction_id' => $sTempId, 'host_class' => get_class($oOrg), 'host_att_code' => 'parent_id',]];
|
||||
$this->oConfig->SetConfigTemporaryForce(true);
|
||||
$this->oConfig->SetConfigTemporaryLifetime(3000);
|
||||
|
||||
$this->assertEquals(0, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
$this->oManager->HandleTemporaryObjects($oOrg, $aContext);
|
||||
$this->assertEquals(1, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
|
||||
$aContext = ['finalize' => ['transaction_id' => $sTempId,]];
|
||||
$this->oManager->HandleTemporaryObjects($oOrg, $aContext);
|
||||
$this->assertEquals(0, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
}
|
||||
|
||||
public function testHandleDeletedTemporaryObjects()
|
||||
{
|
||||
$sTempId = 'testHandleTemporaryObjectsDelete';
|
||||
$oRepository = TemporaryObjectRepository::GetInstance();
|
||||
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$oOrgTemp = $this->CreateTestOrganization();
|
||||
$oOrg->Set('parent_id', $oOrgTemp->GetKey());
|
||||
$oOrg->DBUpdate();
|
||||
|
||||
// Create a temporary delete
|
||||
$this->assertEquals(0, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
$oTemporaryObjectDescriptor = TemporaryObjectManager::GetInstance()->CreateTemporaryObject($sTempId, get_class($oOrgTemp), $oOrgTemp->Get('id'), TemporaryObjectHelper::OPERATION_DELETE);
|
||||
$oTemporaryObjectDescriptor->Set('host_class', get_class($oOrg));
|
||||
$oTemporaryObjectDescriptor->Set('host_id', $oOrg->GetKey());
|
||||
$oTemporaryObjectDescriptor->Set('host_att_code', 'parent_id');
|
||||
$oTemporaryObjectDescriptor->DBUpdate();
|
||||
$this->assertEquals(1, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
|
||||
$aContext = ['finalize' => ['transaction_id' => $sTempId,]];
|
||||
$this->oManager->HandleTemporaryObjects($oOrg, $aContext);
|
||||
$this->assertEquals(0, $oRepository->CountTemporaryObjectsByTempId($sTempId));
|
||||
$oDeletedObject = \MetaModel::GetObject(get_class($oOrgTemp), $oOrgTemp->Get('id'), false);
|
||||
$this->assertNull($oDeletedObject);
|
||||
}
|
||||
|
||||
|
||||
private function CreateTemporaryObject($sTempId, $oDBObject, int $iLifetime, string $sOperation)
|
||||
{
|
||||
$this->oConfig->SetConfigTemporaryLifetime($iLifetime);
|
||||
$this->oConfig->SetConfigTemporaryForce(true);
|
||||
|
||||
return $this->oManager->CreateTemporaryObject($sTempId, get_class($oDBObject), $oDBObject->GetKey(), $sOperation);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Service\TemporaryObjects;
|
||||
|
||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectConfig;
|
||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectHelper;
|
||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectManager;
|
||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectRepository;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use DBObject;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class TemporaryObjectRepositoryTest extends ItopDataTestCase
|
||||
{
|
||||
const USE_TRANSACTION = true;
|
||||
const CREATE_TEST_ORG = false;
|
||||
|
||||
private TemporaryObjectConfig $oTemporaryObjectConfig;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->oTemporaryObjectConfig = TemporaryObjectConfig::GetInstance();
|
||||
}
|
||||
|
||||
public function testSearchByExpired()
|
||||
{
|
||||
$sTempId = 'testSearchByExpired';
|
||||
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$oRepository = TemporaryObjectRepository::GetInstance();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, 3000);
|
||||
$oObjectSet = $oRepository->SearchByExpired();
|
||||
$this->assertEquals(0, $oObjectSet->Count());
|
||||
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, -1);
|
||||
$oObjectSet = $oRepository->SearchByExpired();
|
||||
$this->assertEquals(1, $oObjectSet->Count());
|
||||
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, -1);
|
||||
$oObjectSet = $oRepository->SearchByExpired();
|
||||
$this->assertEquals(2, $oObjectSet->Count());
|
||||
}
|
||||
|
||||
public function testSearchByTempId()
|
||||
{
|
||||
$sTempId = 'testSearchByTempId';
|
||||
|
||||
// First temp object
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$oDescriptor = $this->CreateTemporaryObject($sTempId, $oOrg, 3000);
|
||||
$oRepository = TemporaryObjectRepository::GetInstance();
|
||||
$oObjectSet = $oRepository->SearchByTempId($sTempId);
|
||||
$this->assertEquals(1, $oObjectSet->Count());
|
||||
$oDBObject = $oObjectSet->Fetch();
|
||||
$this->assertEquals($oDescriptor->GetKey(), $oDBObject->GetKey());
|
||||
$this->assertEquals(get_class($oDescriptor), get_class($oDBObject));
|
||||
|
||||
// Second temp object
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, 3000);
|
||||
$oObjectSet = $oRepository->SearchByTempId($sTempId);
|
||||
$this->assertEquals(2, $oObjectSet->Count());
|
||||
}
|
||||
|
||||
public function testCountTemporaryObjectsByTempId()
|
||||
{
|
||||
$sTempId = 'testCountTemporaryObjectsByTempId';
|
||||
|
||||
// First temp object
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, 3000);
|
||||
$oRepository = TemporaryObjectRepository::GetInstance();
|
||||
$iCount = $oRepository->CountTemporaryObjectsByTempId($sTempId);
|
||||
$this->assertEquals(1, $iCount);
|
||||
|
||||
// Second temp object
|
||||
$oOrg = $this->CreateTestOrganization();
|
||||
$this->CreateTemporaryObject($sTempId, $oOrg, 3000);
|
||||
$iCount = $oRepository->CountTemporaryObjectsByTempId($sTempId);
|
||||
$this->assertEquals(2, $iCount);
|
||||
}
|
||||
|
||||
private function CreateTemporaryObject($sTempId, DBObject $oDBObject, int $iLifetime)
|
||||
{
|
||||
$this->oTemporaryObjectConfig->SetConfigTemporaryLifetime($iLifetime);
|
||||
$this->oTemporaryObjectConfig->SetConfigTemporaryForce(true);
|
||||
|
||||
$oManager = TemporaryObjectManager::GetInstance();
|
||||
|
||||
return $oManager->CreateTemporaryObject($sTempId, get_class($oDBObject), $oDBObject->GetKey(), TemporaryObjectHelper::OPERATION_CREATE);
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ JSON;
|
||||
$iId = $aJson['objects'][$sUserRequestKey]['key'];
|
||||
|
||||
$sExpectedJsonOuput = <<<JSON
|
||||
{"objects":{"UserRequest::$iId":{"code":0,"message":"created","class":"UserRequest","key":$iId,"fields":{"id":$iId}}},"code":0,"message":null}
|
||||
{"objects":{"UserRequest::$iId":{"code":0,"message":"created","class":"UserRequest","key":"$iId","fields":{"id":"$iId"}}},"code":0,"message":null}
|
||||
JSON;
|
||||
$this->assertJsonStringEqualsJsonString($sExpectedJsonOuput, $sOutputJson);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user