diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php index e8a9f4a09..64bd7bd4b 100644 --- a/core/attributedef.class.inc.php +++ b/core/attributedef.class.inc.php @@ -6460,7 +6460,13 @@ class AttributeDateTime extends AttributeDBField try { $oDate = new DateTimeImmutable($sDefaultValue); } catch (Exception $e) { - $oDate = new DateTimeImmutable(Expression::FromOQL($sDefaultValue)->Evaluate([])); + try { + $oDate = new DateTimeImmutable(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(); + } + } return $oDate->format($this->GetInternalFormat()); } diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php index 0f2c27a3e..9c6f47425 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php @@ -1492,6 +1492,12 @@ abstract class ItopDataTestCase extends ItopTestCase $this->assertEquals(1, $oSet->Count(), $sMessage); } + protected function AssertLastErrorLogEntryContains(string $sNeedle, string $sMessage = '') + { + $aLastLines = self::ReadTail(APPROOT.'/log/error.log'); + $this->assertStringContainsString($sNeedle, $aLastLines[0], $sMessage); + } + static protected function StartStopwatchInThePast(DBObject $oObject, string $sStopwatchAttCode, int $iDelayInSecond) { $iStartDate = time() - $iDelayInSecond; diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php index 52cbe3436..fda90fbbb 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php @@ -572,4 +572,35 @@ abstract class ItopTestCase extends TestCase } return parent::bootKernel($options); } + + /** + * @author Ain Tohvri + */ + static protected function ReadTail($sFilename, $iLines = 1) + { + $handle = fopen($sFilename, "r"); + $iLineCounter = $iLines; + $iPos = -2; + $bBeginning = false; + $aLines = array(); + while ($iLineCounter > 0) { + $sChar = " "; + while ($sChar != "\n") { + if(fseek($handle, $iPos, SEEK_END) == -1) { + $bBeginning = true; + break; + } + $sChar = fgetc($handle); + $iPos --; + } + $iLineCounter --; + if ($bBeginning) { + rewind($handle); + } + $aLines[$iLines - $iLineCounter - 1] = fgets($handle); + if ($bBeginning) break; + } + fclose ($handle); + return array_reverse($aLines); + } } diff --git a/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php b/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php index 5b25b455b..82d5c4a17 100644 --- a/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php +++ b/tests/php-unit-tests/unitary-tests/core/AttributeDefinitionTest.php @@ -254,6 +254,20 @@ PHP self::assertNull($defaultValue, 'Empty default value for DateTime attribute should give null default value'); } + public function testDateTimeInvalidDefaultReturnsNullAsDefaultValue() + { + // Given + $oDateAttribute = new AttributeDateTime('start_date', ['sql' => 'start_date', 'is_null_allowed' => false, 'default_value' => 'zabugomeuh', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]); + $oDateAttribute->SetHostClass('WorkOrder'); + + //When + $defaultValue = $oDateAttribute->GetDefaultValue(); + + // Then + self::assertNull($defaultValue, 'Invalid default value for DateTime attribute should give null default value'); + 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"); + } + public function testDateEmptyDefaultReturnsNullAsDefaultValue() { // Given @@ -267,6 +281,20 @@ PHP self::assertNull($defaultValue, 'Empty default value for Date attribute should give null default value'); } + public function testDateInvalidDefaultReturnsNullAsDefaultValue() + { + // Given + $oDateAttribute = new AttributeDate('start_date', ['sql' => 'start_date', 'is_null_allowed' => false, 'default_value' => 'zabugomeuh', 'allowed_values' => null, 'depends_on' => [], 'always_load_in_tables' => false]); + $oDateAttribute->SetHostClass('WorkOrder'); + + //When + $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"); + + // Then + self::assertNull($defaultValue, 'Invalid default value for Date attribute should give null default value'); + } + public function testDateTimeNowAsDefaultGivesCurrentDateAsDefaultValue() { @@ -287,6 +315,7 @@ PHP // Then $sNow = date($oDateAttribute->GetInternalFormat()); self::assertEquals($sNow, $defaultValue, 'Now as default value for DateTime attribute should give current date as default value'); + }