Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
wazelin committed Sep 8, 2022
2 parents ff1c20d + 3c38111 commit 5953596
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 4 deletions.
5 changes: 5 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
coverage:
status:
project:
default:
threshold: 1%
40 changes: 36 additions & 4 deletions src/qtism/runtime/tests/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@
*/
class Utils
{
private const MAX_ENTRY_RESTRICTION_PATTERN = '/^\/\^(?P<splitPattern>\([^{]+)\{(?P<min>\d+)(?:(?P<isRange>,)|,(?P<max>\d+))?\}\$\/\w*$/';
private const CLOSE_MATCH_GROUP_TOKEN = ')';
private const OPEN_MATCH_GROUP_TOKEN = '(';

/**
* Whether or not a QtiDatatype object is considered valid against a given ResponseValidityConstraint object $constraint.
* Whether a QtiDatatype object is considered valid against a given ResponseValidityConstraint object $constraint.
*
* Min and Max constraints will be checked first, followed by the patternMask check.
*
Expand All @@ -50,10 +54,9 @@ class Utils
*
* Moreover, null values given as a $response will be considered to have no cardinality i.e. count($response) = 0.
*
* @param QtiDatatype $response
* @param QtiDatatype|null $response
* @param ResponseValidityConstraint $constraint
* @return bool
* @throws RuntimeException If An error occurred while validating a patternMask.
*/
public static function isResponseValid(QtiDatatype $response = null, ResponseValidityConstraint $constraint)
{
Expand Down Expand Up @@ -86,13 +89,24 @@ public static function isResponseValid(QtiDatatype $response = null, ResponseVal

$patternMask = OperatorUtils::prepareXsdPatternForPcre($patternMask);

$isMaxEntryRestriction = preg_match(self::MAX_ENTRY_RESTRICTION_PATTERN, $patternMask, $matches)
&& self::isSingleMatchGroup($patternMask);

foreach ($values as $value) {
$result = @preg_match($patternMask, $value);

if ($result === 0) {
return false;
} elseif ($result === false) {
throw new RuntimeException(OperatorUtils::lastPregErrorMessage());
if ($isMaxEntryRestriction) {
[$splitPattern, $min, $max] = self::extractMaxEntryRestrictionsRestrictions($matches);
$entries = count(preg_split("/$splitPattern/", $value)) - 1;
if ($entries > $max || $entries < $min) {
return false;
}
} else {
throw new RuntimeException(OperatorUtils::lastPregErrorMessage());
}
}
}
}
Expand Down Expand Up @@ -125,4 +139,22 @@ public static function isResponseValid(QtiDatatype $response = null, ResponseVal

return true;
}

private static function isSingleMatchGroup(string $patternMask): bool
{
$closeBracketPosition = strpos($patternMask, self::CLOSE_MATCH_GROUP_TOKEN);
return strpos(substr($patternMask, $closeBracketPosition), self::OPEN_MATCH_GROUP_TOKEN) === false;
}

/**
* @return array [(string)$splitPattern, (int)$min, (int)$max]
*/
private static function extractMaxEntryRestrictionsRestrictions(array $matches): array
{
extract($matches);
$isRange = !empty($isRange);
$max ??= $isRange ? PHP_INT_MAX : $min;

return [$splitPattern, (int)$min, (int)$max];
}
}
Loading

0 comments on commit 5953596

Please sign in to comment.