mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-06-10 16:46:38 -04:00
Fix overly lenient date validation (#4574)
* Fix overly lenient date validation - In the past date validation would roll over dates that didn't exist into the next month. Now they return an error. Signed-off-by: objec <objecttothis@gmail.com> * Refactor naming - Refactor parameter - Refactor function name. Signed-off-by: objec <objecttothis@gmail.com> * Add unit tests for LocaleHelper Signed-off-by: objec <objecttothis@gmail.com> * Remove files from being tracked. Signed-off-by: objec <objecttothis@gmail.com> --------- Signed-off-by: objec <objecttothis@gmail.com>
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -56,6 +56,7 @@ $RECYCLE.BIN/
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Other
|
||||
build/
|
||||
generate_languages.php
|
||||
dist
|
||||
docs
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}}
|
||||
@@ -1,38 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites>
|
||||
<testsuite name="/app/phpunit.xml.dist" tests="29" assertions="44" errors="0" failures="0" skipped="0" time="0.029097">
|
||||
<testsuite name="App" tests="29" assertions="44" errors="0" failures="0" skipped="0" time="0.029097">
|
||||
<testsuite name="Tests\Libraries\Token_libTest" file="/app/tests/Libraries/Token_libTest.php" tests="29" assertions="44" errors="0" failures="0" skipped="0" time="0.029097">
|
||||
<testcase name="testRenderReturnsInputStringWhenNoTokens" file="/app/tests/Libraries/Token_libTest.php" line="18" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.007667"/>
|
||||
<testcase name="testRenderHandlesStringWithPercentNotInDateFormat" file="/app/tests/Libraries/Token_libTest.php" line="25" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.004001"/>
|
||||
<testcase name="testRenderHandlesInvalidDateFormatPercentDashPercent" file="/app/tests/Libraries/Token_libTest.php" line="33" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.001162"/>
|
||||
<testcase name="testRenderHandlesInvalidDateFormatPercentYPercentQPercentBad" file="/app/tests/Libraries/Token_libTest.php" line="41" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000766"/>
|
||||
<testcase name="testRenderHandlesStringWithPercentAPercent" file="/app/tests/Libraries/Token_libTest.php" line="48" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000613"/>
|
||||
<testcase name="testRenderHandlesExtremelyLongString" file="/app/tests/Libraries/Token_libTest.php" line="55" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000513"/>
|
||||
<testcase name="testRenderHandlesStringWithMultiplePercentSymbols" file="/app/tests/Libraries/Token_libTest.php" line="62" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.000589"/>
|
||||
<testcase name="testRenderHandlesStringWithOnlyPercentSymbol" file="/app/tests/Libraries/Token_libTest.php" line="70" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000578"/>
|
||||
<testcase name="testRenderPreservesTextWithValidDateTokensAndNoOtherTokens" file="/app/tests/Libraries/Token_libTest.php" line="77" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000612"/>
|
||||
<testcase name="testRenderHandlesEmptyString" file="/app/tests/Libraries/Token_libTest.php" line="84" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000503"/>
|
||||
<testcase name="testScanExtractsTokens" file="/app/tests/Libraries/Token_libTest.php" line="91" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.000578"/>
|
||||
<testcase name="testScanExtractsTokensWithLength" file="/app/tests/Libraries/Token_libTest.php" line="98" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.000501"/>
|
||||
<testcase name="testScanReturnsEmptyArrayForNoTokens" file="/app/tests/Libraries/Token_libTest.php" line="105" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000513"/>
|
||||
<testcase name="testRenderHandlesConsecutivePercentSigns" file="/app/tests/Libraries/Token_libTest.php" line="111" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.000628"/>
|
||||
<testcase name="testRenderHandlesEscapedPercentSigns" file="/app/tests/Libraries/Token_libTest.php" line="119" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000626"/>
|
||||
<testcase name="testRenderHandlesUnclosedBraces" file="/app/tests/Libraries/Token_libTest.php" line="126" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000617"/>
|
||||
<testcase name="testRenderHandlesUnopenedBraces" file="/app/tests/Libraries/Token_libTest.php" line="133" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000620"/>
|
||||
<testcase name="testRenderHandlesVeryLongStringWithDate" file="/app/tests/Libraries/Token_libTest.php" line="140" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.000599"/>
|
||||
<testcase name="testRenderHandlesMultipleDates" file="/app/tests/Libraries/Token_libTest.php" line="148" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000593"/>
|
||||
<testcase name="testRenderHandlesValidYearFormat" file="/app/tests/Libraries/Token_libTest.php" line="155" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000688"/>
|
||||
<testcase name="testRenderHandlesValidMonthFormat" file="/app/tests/Libraries/Token_libTest.php" line="162" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000611"/>
|
||||
<testcase name="testRenderHandlesValidDayFormat" file="/app/tests/Libraries/Token_libTest.php" line="169" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000627"/>
|
||||
<testcase name="testRenderHandlesFullDateFormat" file="/app/tests/Libraries/Token_libTest.php" line="176" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="1" time="0.000757"/>
|
||||
<testcase name="testRenderHandlesPercentB" file="/app/tests/Libraries/Token_libTest.php" line="183" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="3" time="0.000766"/>
|
||||
<testcase name="testRenderHandlesPercentA" file="/app/tests/Libraries/Token_libTest.php" line="192" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="3" time="0.000703"/>
|
||||
<testcase name="testRenderHandlesComplexPercentFormat" file="/app/tests/Libraries/Token_libTest.php" line="201" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.000669"/>
|
||||
<testcase name="testRenderDoesNotReplaceInvalidFormatSpecifiers" file="/app/tests/Libraries/Token_libTest.php" line="209" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.000646"/>
|
||||
<testcase name="testRenderReplacesTimezoneFormat" file="/app/tests/Libraries/Token_libTest.php" line="217" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.000811"/>
|
||||
<testcase name="testScanWorksWithMixedContent" file="/app/tests/Libraries/Token_libTest.php" line="225" class="Tests\Libraries\Token_libTest" classname="Tests.Libraries.Token_libTest" assertions="2" time="0.000540"/>
|
||||
</testsuite>
|
||||
</testsuite>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
@@ -1,87 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Test Documentation</title>
|
||||
<style>
|
||||
body {
|
||||
text-rendering: optimizeLegibility;
|
||||
font-family: Source SansSerif Pro, Arial, sans-serif;
|
||||
font-variant-ligatures: common-ligatures;
|
||||
font-kerning: normal;
|
||||
margin-left: 2rem;
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
body > ul > li {
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: larger;
|
||||
text-decoration-line: underline;
|
||||
text-decoration-thickness: 2px;
|
||||
margin: 0;
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0 0 2rem;
|
||||
padding: 0 0 0 1rem;
|
||||
text-indent: -1rem;
|
||||
}
|
||||
|
||||
.success:before {
|
||||
color: #4e9a06;
|
||||
content: '✓';
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
|
||||
.defect {
|
||||
color: #a40000;
|
||||
}
|
||||
|
||||
.defect:before {
|
||||
color: #a40000;
|
||||
content: '✗';
|
||||
padding-right: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Token_lib (Tests\Libraries\Token_lib)</h2>
|
||||
<ul>
|
||||
<li class="success">Render returns input string when no tokens</li>
|
||||
<li class="success">Render handles string with percent not in date format</li>
|
||||
<li class="success">Render handles invalid date format percent dash percent</li>
|
||||
<li class="success">Render handles invalid date format percent y percent q percent bad</li>
|
||||
<li class="success">Render handles string with percent a percent</li>
|
||||
<li class="success">Render handles extremely long string</li>
|
||||
<li class="success">Render handles string with multiple percent symbols</li>
|
||||
<li class="success">Render handles string with only percent symbol</li>
|
||||
<li class="success">Render preserves text with valid date tokens and no other tokens</li>
|
||||
<li class="success">Render handles empty string</li>
|
||||
<li class="success">Scan extracts tokens</li>
|
||||
<li class="success">Scan extracts tokens with length</li>
|
||||
<li class="success">Scan returns empty array for no tokens</li>
|
||||
<li class="success">Render handles consecutive percent signs</li>
|
||||
<li class="success">Render handles escaped percent signs</li>
|
||||
<li class="success">Render handles unclosed braces</li>
|
||||
<li class="success">Render handles unopened braces</li>
|
||||
<li class="success">Render handles very long string with date</li>
|
||||
<li class="success">Render handles multiple dates</li>
|
||||
<li class="success">Render handles valid year format</li>
|
||||
<li class="success">Render handles valid month format</li>
|
||||
<li class="success">Render handles valid day format</li>
|
||||
<li class="success">Render handles full date format</li>
|
||||
<li class="success">Render handles percent b</li>
|
||||
<li class="success">Render handles percent a</li>
|
||||
<li class="success">Render handles complex percent format</li>
|
||||
<li class="success">Render does not replace invalid format specifiers</li>
|
||||
<li class="success">Render replaces timezone format</li>
|
||||
<li class="success">Scan works with mixed content</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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
|
||||
|
||||
59
tests/helpers/LocaleHelperTest.php
Normal file
59
tests/helpers/LocaleHelperTest.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
use CodeIgniter\Config\Factories;
|
||||
use CodeIgniter\Test\CIUnitTestCase;
|
||||
use Config\OSPOS;
|
||||
|
||||
class LocaleHelperTest extends CIUnitTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once __DIR__ . '/../../app/Helpers/locale_helper.php';
|
||||
|
||||
$config = new OSPOS();
|
||||
$config->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'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user