diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index 6a2081cb3..cdbb17742 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -6464,6 +6464,7 @@ class AttributeDateTime extends AttributeDBField $sDefaultDate = Expression::FromOQL('"'.$sDefaultValue.'"')->Evaluate([]); } catch (Exception $e) { IssueLog::Error("Invalid default value '$sDefaultValue' for field '{$this->GetCode()}' on class '{$this->GetHostClass()}', defaulting to null"); + return $this->GetNullValue(); } } diff --git a/sources/Application/UI/Base/Layout/NavigationMenu/NavigationMenu.php b/sources/Application/UI/Base/Layout/NavigationMenu/NavigationMenu.php index 085641e88..7e9a39c17 100644 --- a/sources/Application/UI/Base/Layout/NavigationMenu/NavigationMenu.php +++ b/sources/Application/UI/Base/Layout/NavigationMenu/NavigationMenu.php @@ -388,7 +388,7 @@ class NavigationMenu extends UIBlock implements iKeyboardShortcut <<IsInterfaceImplementation($sPHPClass, $sInterface)) { - $aMatchingClasses[] = $sPHPClass; + if ($this->bCheckInterfaceImplementation && ! $this->IsInterfaceImplementation($sPHPClass, $sInterface)) { + continue; } + + if (! class_exists($sPHPClass)){ + continue; + } + + $aMatchingClasses[] = $sPHPClass; } if ($this->GetCacheMode() !== self::CACHE_NONE) { @@ -241,7 +248,17 @@ class InterfaceDiscovery public function ReadClassesFromCache(string $sKey): array { - return $this->oCacheService->Fetch('InterfaceDiscovery', $sKey); + $aClasses = $this->oCacheService->Fetch('InterfaceDiscovery', $sKey); + + $aRealClasses = []; + foreach ($aClasses as $sPHPClass){ + if (! class_exists($sPHPClass)){ + continue; + } + + $aRealClasses[]=$sPHPClass; + } + return $aRealClasses; } protected function SaveClassesToCache(string $sKey, array $aMatchingClasses, array $aMoreInfo): void diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php index 05bda7bbd..00a0d7f05 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php @@ -992,6 +992,14 @@ abstract class ItopDataTestCase extends ItopTestCase } } + protected function AssertLastErrorLogEntryContains(string $sNeedle, string $sMessage = ''): void + { + $aLastLines = self::ReadTail(APPROOT.'/log/error.log'); + $this->assertStringContainsString($sNeedle, $aLastLines[0], $sMessage); + } + + + /** * Import a set of XML files describing a consistent set of iTop objects * @param string[] $aFiles diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php index 62e913b75..6ac2ec5fa 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php @@ -557,10 +557,8 @@ abstract class ItopTestCase extends TestCase static protected function AssertDateEqualsNow($sActualDate, $sMessage = ''): void { $oActualDate = \DateTime::createFromFormat(\AttributeDate::GetInternalFormat(), $sActualDate); - $oNow = new DateTime(); - + $oNow = new \DateTime(); $iTimeInterval = $oNow->diff($oActualDate)->s; - self::assertLessThan(2, $iTimeInterval, $sMessage); } /** @@ -569,10 +567,8 @@ abstract class ItopTestCase extends TestCase static protected function AssertDateTimeEqualsNow($sActualDate, $sMessage = ''): void { $oActualDateTime = \DateTime::createFromFormat(\AttributeDateTime::GetInternalFormat(), $sActualDate); - $oNow = new DateTime(); - + $oNow = new \DateTime(); $iTimeInterval = $oNow->diff($oActualDateTime)->s; - self::assertLessThan(2, $iTimeInterval, $sMessage); } diff --git a/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php b/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php index 85462cc8c..1070db8e9 100644 --- a/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php +++ b/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php @@ -273,12 +273,13 @@ PHP { $oDateAttribute = $this->GivenAttribute(\WorkOrder::class, 'start_date', AttributeDate::class, 'zabugomeuh', false); - $defaultValue = $oDateAttribute->GetDefaultValue(); - + $defaultValue = $oDateAttribute->GetDefaultValue() self::AssertLastErrorLogEntryContains("Invalid default value 'zabugomeuh' for field 'start_date' on class 'WorkOrder', defaulting to null", "Last error log entry should contain a meaningful message"); + self::assertNull($defaultValue, 'Invalid default value for Date attribute should give null default value'); } + public function testDateInvalidDefaultReturnsNullAsDefaultValue_Case2() { $oDateAttribute = $this->GivenAttribute(\WorkOrder::class, 'start_date', AttributeDate::class, '"27/01/2025"', false); @@ -292,18 +293,18 @@ PHP public function testDateTimeNowAsDefaultGivesCurrentDateAsDefaultValue() { $oDateAttribute = $this->GivenAttribute(\WorkOrder::class, 'start_date', AttributeDateTime::class, 'NOW()', false); - $sDefaultValue = $oDateAttribute->GetDefaultValue(); self::AssertDateTimeEqualsNow($sDefaultValue, 'NOW() should be evaluated as the current date and time'); } + public function testDateNowAsDefaultGivesCurrentDateAsDefaultValue() { $oDateAttribute = $this->GivenAttribute(\WorkOrder::class, 'start_date', AttributeDate::class, 'NOW()', false); - $sDefaultValue = $oDateAttribute->GetDefaultValue(); + $defaultValue = $oDateAttribute->GetDefaultValue(); - self::AssertDateEqualsNow($sDefaultValue, 'NOW() should be evaluated as the current date'); + self::AssertDateEqualsNow($defaultValue, 'NOW() should be evaluated as the current date'); } public function testDateTimeIntervalAsDefaultGivesCorrectDateAsDefaultValue() diff --git a/tests/php-unit-tests/unitary-tests/sources/Service/InterfaceDiscovery/InterfaceDiscoveryTest.php b/tests/php-unit-tests/unitary-tests/sources/Service/InterfaceDiscovery/InterfaceDiscoveryTest.php index 5f3689072..1a3f2aab1 100644 --- a/tests/php-unit-tests/unitary-tests/sources/Service/InterfaceDiscovery/InterfaceDiscoveryTest.php +++ b/tests/php-unit-tests/unitary-tests/sources/Service/InterfaceDiscovery/InterfaceDiscoveryTest.php @@ -26,6 +26,7 @@ class InterfaceDiscoveryTest extends ItopDataTestCase protected function tearDown(): void { + $this->SetNonPublicProperty($this->oInterfaceDiscovery, 'bCheckInterfaceImplementation', true); $this->SetNonPublicProperty(InterfaceDiscovery::GetInstance(), 'aForcedClassMap', null); $this->oCacheService->SetStorageRootDir(null); self::RecurseRmdir($this->sCacheRootDir); @@ -49,6 +50,40 @@ class InterfaceDiscoveryTest extends ItopDataTestCase ); } + /** + * @covers N°8143 - Setup page in error + */ + public function testShouldSelectTheRequestedItopClassesAndExcludeUnexistingOnes() + { + $this->SetNonPublicProperty($this->oInterfaceDiscovery, 'bCheckInterfaceImplementation', false); + $this->GivenClassMap([ + 'Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory2' => APPROOT . '/sources/Application/UI/Base/Component/Alert/AlertUIBlockFactory.php', + 'Combodo\iTop\Application\UI\Base\Component\ButtonGroup\ButtonGroupUIBlockFactory2' => APPROOT . '/sources/Application/UI/Base/Component/ButtonGroup/ButtonGroupUIBlockFactory.php', + ]); + + $this->AssertArraysHaveSameItems([], $this->oInterfaceDiscovery->FindItopClasses(iUIBlockFactory::class)); + } + + /** + * @covers N°8143 - Setup page in error + */ + public function testReadClassesFromCache_ShouldExcludeUnexistingClasses() + { + $oCacheService = $this->createMock(DataModelDependantCache::class); + $aCachedRealClasses = [ + 'Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory', + 'Combodo\iTop\Application\UI\Base\Component\ButtonGroup\ButtonGroupUIBlockFactory2', + ]; + $oCacheService->expects($this->once()) + ->method('Fetch') + ->with('InterfaceDiscovery', '123') + ->willReturn($aCachedRealClasses); + + $this->oInterfaceDiscovery->SetCacheService($oCacheService); + + $this->AssertArraysHaveSameItems([ 'Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory'], $this->oInterfaceDiscovery->ReadClassesFromCache('123')); + } + public function testShouldExcludeAliases() { $this->GivenClassMap([ @@ -87,7 +122,7 @@ class InterfaceDiscoveryTest extends ItopDataTestCase $this->assertGreaterThan(0, count($this->oInterfaceDiscovery->FindItopClasses(iUIBlockFactory::class))); $this->AssertDirectoryListingEquals([ 'autoload_classmaps.php', - '1ab1e62be3e9984a8176deeb20f049b1_iUIBlockFactory.php' + '1ab1e62be3e9984a8176deeb20f049b1_iUIBlockFactory.php', ], $this->sCacheRootDir.'/InterfaceDiscovery'); }