diff --git a/.gitignore b/.gitignore index 1ef8696fa..94a9b3315 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ $RECYCLE.BIN/ .com.apple.timemachine.donotpresent # Other +build/ generate_languages.php dist docs diff --git a/app/Controllers/Items.php b/app/Controllers/Items.php index b5348a144..374c7169c 100644 --- a/app/Controllers/Items.php +++ b/app/Controllers/Items.php @@ -1239,7 +1239,7 @@ class Items extends Secure_Controller } break; case DATE: - if (!valid_date($attributeValue) && !empty($attributeValue)) { + if (!isValidDate($attributeValue) && !empty($attributeValue)) { log_message('error', "'$attributeValue' is not an acceptable DATE value. The value must match the set locale."); return true; } diff --git a/app/Helpers/locale_helper.php b/app/Helpers/locale_helper.php index 3ae8f71f1..c540f4079 100644 --- a/app/Helpers/locale_helper.php +++ b/app/Helpers/locale_helper.php @@ -639,13 +639,14 @@ function dateformat_bootstrap(string $php_format): string } /** - * @param string $date + * @param string $candidate * @return bool */ -function valid_date(string $date): bool // TODO: need a better name for $date. Perhaps $candidate. Also the function name would be better as is_valid_date() +function isValidDate(string $candidate): bool { $config = config(OSPOS::class)->settings; - return (DateTime::createFromFormat($config['dateformat'], $date)); + $parsed = DateTime::createFromFormat($config['dateformat'], $candidate); + return $parsed !== false && $parsed->format($config['dateformat']) === $candidate; } /** diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php index 33cbdac43..1ca42d6c8 100644 --- a/app/Models/Attribute.php +++ b/app/Models/Attribute.php @@ -388,7 +388,7 @@ class Attribute extends Model foreach ($builder->get()->getResult() as $attribute) { switch ($to) { case DATE: - $success = valid_date($attribute->attribute_value); + $success = isValidDate($attribute->attribute_value); break; case DECIMAL: $success = valid_decimal($attribute->attribute_value); diff --git a/build/.phpunit.cache/test-results b/build/.phpunit.cache/test-results deleted file mode 100644 index f218fd058..000000000 --- a/build/.phpunit.cache/test-results +++ /dev/null @@ -1 +0,0 @@ -{"version":2,"defects":{"Token_libTest::testRenderHandlesSpecialCharacters":8,"Token_libTest::testRenderHandlesUnicode":8,"Token_libTest::testRenderHandlesNewLines":8,"Token_libTest::testRenderHandlesTabs":8,"Token_libTest::testRenderHandlesDateAtStart":8,"Token_libTest::testRenderHandlesSqlInjectionAttempt":8,"Token_libTest::testRenderHandlesVeryLongStringWithDate":8,"Token_libTest::testRenderHandlesMultipleDates":8,"Token_libTest::testRenderDoesNotReplaceInvalidFormatSpecifiers":7},"times":{"Token_libTest::testRenderReturnsInputStringWhenNoTokens":0.002,"Token_libTest::testRenderHandlesStringWithPercentNotInDateFormat":0.004,"Token_libTest::testRenderHandlesInvalidDateFormatPercentDashPercent":0.001,"Token_libTest::testRenderHandlesInvalidDateFormatPercentYPercentQPercentBad":0,"Token_libTest::testRenderHandlesStringWithPercentAPercent":0,"Token_libTest::testRenderHandlesExtremelyLongString":0,"Token_libTest::testRenderHandlesStringWithMultiplePercentSymbols":0,"Token_libTest::testRenderHandlesStringWithOnlyPercentSymbol":0,"Token_libTest::testRenderPreservesTextWithValidDateTokensAndNoOtherTokens":0,"Token_libTest::testRenderHandlesEmptyString":0,"Token_libTest::testScanExtractsTokens":0,"Token_libTest::testScanExtractsTokensWithLength":0,"Token_libTest::testScanReturnsEmptyArrayForNoTokens":0,"Token_libTest::testRenderHandlesConsecutivePercentSigns":0,"Token_libTest::testRenderHandlesEscapedPercentSigns":0,"Token_libTest::testRenderHandlesSpecialCharacters":0.005,"Token_libTest::testRenderHandlesUnicode":0,"Token_libTest::testRenderHandlesNewLines":0,"Token_libTest::testRenderHandlesTabs":0,"Token_libTest::testRenderHandlesUnclosedBraces":0,"Token_libTest::testRenderHandlesUnopenedBraces":0,"Token_libTest::testRenderHandlesDateAtStart":0,"Token_libTest::testRenderHandlesSqlInjectionAttempt":0,"Token_libTest::testRenderHandlesVeryLongStringWithDate":0,"Token_libTest::testRenderHandlesMultipleDates":0,"Token_libTest::testRenderHandlesValidYearFormat":0,"Token_libTest::testRenderHandlesValidMonthFormat":0,"Token_libTest::testRenderHandlesValidDayFormat":0,"Token_libTest::testRenderHandlesFullDateFormat":0,"Token_libTest::testRenderHandlesPercentB":0,"Token_libTest::testRenderHandlesPercentA":0,"Token_libTest::testRenderHandlesComplexPercentFormat":0,"Token_libTest::testRenderDoesNotReplaceInvalidFormatSpecifiers":0,"Token_libTest::testScanWorksWithMixedContent":0,"Token_libTest::testRenderReplacesTimezoneFormat":0,"Tests\\Libraries\\Token_libTest::testRenderReturnsInputStringWhenNoTokens":0.001,"Tests\\Libraries\\Token_libTest::testRenderHandlesStringWithPercentNotInDateFormat":0.004,"Tests\\Libraries\\Token_libTest::testRenderHandlesInvalidDateFormatPercentDashPercent":0.001,"Tests\\Libraries\\Token_libTest::testRenderHandlesInvalidDateFormatPercentYPercentQPercentBad":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesStringWithPercentAPercent":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesExtremelyLongString":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesStringWithMultiplePercentSymbols":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesStringWithOnlyPercentSymbol":0,"Tests\\Libraries\\Token_libTest::testRenderPreservesTextWithValidDateTokensAndNoOtherTokens":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesEmptyString":0,"Tests\\Libraries\\Token_libTest::testScanExtractsTokens":0,"Tests\\Libraries\\Token_libTest::testScanExtractsTokensWithLength":0,"Tests\\Libraries\\Token_libTest::testScanReturnsEmptyArrayForNoTokens":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesConsecutivePercentSigns":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesEscapedPercentSigns":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesUnclosedBraces":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesUnopenedBraces":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesVeryLongStringWithDate":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesMultipleDates":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesValidYearFormat":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesValidMonthFormat":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesValidDayFormat":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesFullDateFormat":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesPercentB":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesPercentA":0,"Tests\\Libraries\\Token_libTest::testRenderHandlesComplexPercentFormat":0,"Tests\\Libraries\\Token_libTest::testRenderDoesNotReplaceInvalidFormatSpecifiers":0,"Tests\\Libraries\\Token_libTest::testRenderReplacesTimezoneFormat":0,"Tests\\Libraries\\Token_libTest::testScanWorksWithMixedContent":0}} \ No newline at end of file diff --git a/build/logs/logfile.xml b/build/logs/logfile.xml deleted file mode 100644 index 0620ddbf0..000000000 --- a/build/logs/logfile.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/logs/testdox.html b/build/logs/testdox.html deleted file mode 100644 index 90bca5c26..000000000 --- a/build/logs/testdox.html +++ /dev/null @@ -1,87 +0,0 @@ - - - - - Test Documentation - - - -

Token_lib (Tests\Libraries\Token_lib)

- - - \ No newline at end of file diff --git a/build/logs/testdox.txt b/build/logs/testdox.txt deleted file mode 100644 index 1fb7200d4..000000000 --- a/build/logs/testdox.txt +++ /dev/null @@ -1,31 +0,0 @@ -Token_lib (Tests\Libraries\Token_lib) - [x] Render returns input string when no tokens - [x] Render handles string with percent not in date format - [x] Render handles invalid date format percent dash percent - [x] Render handles invalid date format percent y percent q percent bad - [x] Render handles string with percent a percent - [x] Render handles extremely long string - [x] Render handles string with multiple percent symbols - [x] Render handles string with only percent symbol - [x] Render preserves text with valid date tokens and no other tokens - [x] Render handles empty string - [x] Scan extracts tokens - [x] Scan extracts tokens with length - [x] Scan returns empty array for no tokens - [x] Render handles consecutive percent signs - [x] Render handles escaped percent signs - [x] Render handles unclosed braces - [x] Render handles unopened braces - [x] Render handles very long string with date - [x] Render handles multiple dates - [x] Render handles valid year format - [x] Render handles valid month format - [x] Render handles valid day format - [x] Render handles full date format - [x] Render handles percent b - [x] Render handles percent a - [x] Render handles complex percent format - [x] Render does not replace invalid format specifiers - [x] Render replaces timezone format - [x] Scan works with mixed content - diff --git a/tests/helpers/LocaleHelperTest.php b/tests/helpers/LocaleHelperTest.php new file mode 100644 index 000000000..a76dcf00c --- /dev/null +++ b/tests/helpers/LocaleHelperTest.php @@ -0,0 +1,59 @@ +settings = ['dateformat' => 'Y-m-d']; + Factories::injectMock('config', OSPOS::class, $config); + } + + public function testValidDateReturnsTrue(): void + { + $this->assertTrue(isValidDate('2024-06-10')); + } + + public function testInvalidDateFormatReturnsFalse(): void + { + $this->assertFalse(isValidDate('10/06/2024')); + } + + public function testImpossibleDateReturnsFalse(): void + { + $this->assertFalse(isValidDate('2024-13-01')); + } + + public function testPhpDateOverflowReturnsFalse(): void + { + // PHP silently overflows Feb 30 → Mar 1; the format()===candidate check catches this + $this->assertFalse(isValidDate('2024-02-30')); + } + + public function testEmptyStringReturnsFalse(): void + { + $this->assertFalse(isValidDate('')); + } + + public function testLeapDayValidReturnsTrue(): void + { + $this->assertTrue(isValidDate('2024-02-29')); + } + + public function testLeapDayInvalidYearReturnsFalse(): void + { + $this->assertFalse(isValidDate('2023-02-29')); + } + + public function testPartialDateReturnsFalse(): void + { + $this->assertFalse(isValidDate('2024-06')); + } +}