Skip to content

Commit

Permalink
UnitTests - Allow mocking date/time functions in sql
Browse files Browse the repository at this point in the history
Fixes `Civi\ScheduledCommunications\SendTest::testBirthdayMessage`
by overriding not just date functions in php, but also
in mySql.

When a unit test overrides the system time, this will now
propagate to sql queries as well.
  • Loading branch information
colemanw committed Feb 21, 2025
1 parent 0b45244 commit 8f164fe
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CRM/Core/DAO.php
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,9 @@ public function query($query, $i18nRewrite = TRUE) {
if ($i18nRewrite and $dbLocale) {
$query = CRM_Core_I18n_Schema::rewriteQuery($query);
}
if (CIVICRM_UF === 'UnitTests' && CRM_Utils_Time::isOverridden()) {
$query = CRM_Utils_Time::rewriteQuery($query);
}

$ret = parent::query($query);

Expand Down
35 changes: 35 additions & 0 deletions CRM/Utils/Time.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ public static function resetTime() {
self::$callback = NULL;
}

public static function isOverridden(): bool {
return isset(self::$callback);
}

/**
* Approximate time-comparison. $a and $b are considered equal if they
* are within $threshold seconds of each other.
Expand Down Expand Up @@ -234,4 +238,35 @@ public static function getTimeZoneOffsetFromString(string $timezone) {
return NULL;
}

/**
* Rewrite a SQL query to use overridden date/time values for unit tests.
*
* @param string $query
* The query to rewrite.
*
* @return string
* The rewritten query with mocked time replacements.
*/
public static function rewriteQuery(string $query): string {
// Replace date/time expressions with literal values.
$patterns = [
'/\bNOW\(\s*\)/' => '"' . self::date('Y-m-d H:i:s') . '"',
'/\bCURDATE\(\s*\)/' => '"' . self::date('Y-m-d') . '"',
'/\bCURTIME\(\s*\)/' => '"' . self::date('H:i:s') . '"',
'/\bCURRENT_DATE\b/' => '"' . self::date('Y-m-d') . '"',
'/\bCURRENT_TIME\b/' => '"' . self::date('H:i:s') . '"',
'/\bCURRENT_TIMESTAMP\b/' => '"' . self::date('Y-m-d H:i:s') . '"',
'/\bSYSDATE\(\)/' => '"' . self::date('Y-m-d H:i:s') . '"',
'/\bLOCALTIME\b/' => '"' . self::date('Y-m-d H:i:s') . '"',
'/\bLOCALTIMESTAMP\b/' => '"' . self::date('Y-m-d H:i:s') . '"',
];

// Iterate over the patterns and replace matches in the query.
foreach ($patterns as $pattern => $replacement) {
$query = preg_replace($pattern, $replacement, $query);
}

return $query;
}

}

0 comments on commit 8f164fe

Please sign in to comment.