Skip to content

Commit a3e3b29

Browse files
meisterTnickygerritsen
authored andcommitted
Refactor YAML parsing when importing problems
This allows us to add a unit test. No functional changes intended, these will be added later.
1 parent b32fc5c commit a3e3b29

File tree

3 files changed

+332
-67
lines changed

3 files changed

+332
-67
lines changed

webapp/src/Service/ImportProblemService.php

Lines changed: 85 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
2828
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
2929
use Symfony\Component\PropertyAccess\PropertyAccess;
30+
use Symfony\Component\PropertyAccess\PropertyAccessor;
3031
use Symfony\Component\Validator\ConstraintViolationInterface;
3132
use Symfony\Component\Validator\Validator\ValidatorInterface;
3233
use Symfony\Component\Yaml\Yaml;
@@ -261,72 +262,12 @@ public function importZippedProblem(
261262
return null;
262263
}
263264

264-
if ($problemYaml !== false) {
265-
$yamlData = Yaml::parse($problemYaml);
266-
267-
if (!empty($yamlData)) {
268-
$yamlProblemProperties = [];
269-
if (isset($yamlData['name'])) {
270-
if (is_array($yamlData['name'])) {
271-
foreach ($yamlData['name'] as $name) {
272-
// TODO: select a specific instead of the first language.
273-
$yamlProblemProperties['name'] = $name;
274-
break;
275-
}
276-
} else {
277-
$yamlProblemProperties['name'] = $yamlData['name'];
278-
}
279-
}
280-
281-
if (isset($yamlData['type'])) {
282-
$types = explode(' ', $yamlData['type']);
283-
// Validation happens later when we set the properties.
284-
$yamlProblemProperties['typesAsString'] = $types;
285-
} else {
286-
$yamlProblemProperties['typesAsString'] = ['pass-fail'];
287-
}
288-
289-
if (isset($yamlData['validator_flags'])) {
290-
$yamlProblemProperties['special_compare_args'] = $yamlData['validator_flags'];
291-
}
292-
293-
if (isset($yamlData['validation'])
294-
&& ($yamlData['validation'] == 'custom' ||
295-
$yamlData['validation'] == 'custom interactive' ||
296-
$yamlData['validation'] == 'custom multi-pass')) {
297-
if (!$this->searchAndAddValidator($zip, $messages, $externalId, $yamlData['validation'], $problem)) {
298-
return null;
299-
}
300-
301-
if ($yamlData['validation'] == 'custom multi-pass') {
302-
$yamlProblemProperties['typesAsString'][] = 'multi-pass';
303-
}
304-
if ($yamlData['validation'] == 'custom interactive') {
305-
$yamlProblemProperties['typesAsString'][] = 'interactive';
306-
}
307-
}
308-
309-
if (isset($yamlData['limits'])) {
310-
if (isset($yamlData['limits']['memory'])) {
311-
$yamlProblemProperties['memlimit'] = 1024 * $yamlData['limits']['memory'];
312-
}
313-
if (isset($yamlData['limits']['output'])) {
314-
$yamlProblemProperties['outputlimit'] = 1024 * $yamlData['limits']['output'];
315-
}
316-
if (isset($yamlData['limits']['validation_passes'])) {
317-
$problem->setMultipassLimit($yamlData['limits']['validation_passes']);
318-
}
319-
}
320-
321-
foreach ($yamlProblemProperties as $key => $value) {
322-
try {
323-
$propertyAccessor->setValue($problem, $key, $value);
324-
} catch (Exception $e) {
325-
$messages['danger'][] = sprintf('Error: problem.%s: %s', $key, $e->getMessage());
326-
return null;
327-
}
328-
}
329-
}
265+
$validationMode = 'default';
266+
if (!$this->parseYaml($problemYaml, $messages, $validationMode, $propertyAccessor, $problem)) {
267+
return null;
268+
}
269+
if ($validationMode != 'default' && !$this->searchAndAddValidator($zip, $messages, $externalId, $validationMode, $problem)) {
270+
return null;
330271
}
331272

332273
// Add problem statement, also look in obsolete location.
@@ -1047,4 +988,82 @@ private function searchAndAddValidator(ZipArchive $zip, ?array &$messages, strin
1047988
}
1048989
return true;
1049990
}
991+
992+
// Returns true iff the yaml could be parsed correctly.
993+
public static function parseYaml(bool|string $problemYaml, array &$messages, string &$validationMode, PropertyAccessor $propertyAccessor, Problem $problem): bool
994+
{
995+
if ($problemYaml === false) {
996+
// While there was no problem.yaml, there was also no error in parsing.
997+
return true;
998+
}
999+
1000+
$yamlData = Yaml::parse($problemYaml);
1001+
if (empty($yamlData)) {
1002+
// Empty yaml is OK.
1003+
return true;
1004+
}
1005+
1006+
$yamlProblemProperties = [];
1007+
if (isset($yamlData['name'])) {
1008+
if (is_array($yamlData['name'])) {
1009+
foreach ($yamlData['name'] as $name) {
1010+
// TODO: select a specific instead of the first language.
1011+
$yamlProblemProperties['name'] = $name;
1012+
break;
1013+
}
1014+
} else {
1015+
$yamlProblemProperties['name'] = $yamlData['name'];
1016+
}
1017+
}
1018+
1019+
if (isset($yamlData['type'])) {
1020+
$types = explode(' ', $yamlData['type']);
1021+
// Validation happens later when we set the properties.
1022+
$yamlProblemProperties['typesAsString'] = $types;
1023+
} else {
1024+
$yamlProblemProperties['typesAsString'] = ['pass-fail'];
1025+
}
1026+
1027+
if (isset($yamlData['validator_flags'])) {
1028+
$yamlProblemProperties['special_compare_args'] = $yamlData['validator_flags'];
1029+
}
1030+
1031+
$validationMode = 'default';
1032+
if (isset($yamlData['validation'])
1033+
&& ($yamlData['validation'] == 'custom' ||
1034+
$yamlData['validation'] == 'custom interactive' ||
1035+
$yamlData['validation'] == 'custom multi-pass')) {
1036+
$validationMode = $yamlData['validation'];
1037+
1038+
if ($yamlData['validation'] == 'custom multi-pass') {
1039+
$yamlProblemProperties['typesAsString'][] = 'multi-pass';
1040+
}
1041+
if ($yamlData['validation'] == 'custom interactive') {
1042+
$yamlProblemProperties['typesAsString'][] = 'interactive';
1043+
}
1044+
}
1045+
1046+
if (isset($yamlData['limits'])) {
1047+
if (isset($yamlData['limits']['memory'])) {
1048+
$yamlProblemProperties['memlimit'] = 1024 * $yamlData['limits']['memory'];
1049+
}
1050+
if (isset($yamlData['limits']['output'])) {
1051+
$yamlProblemProperties['outputlimit'] = 1024 * $yamlData['limits']['output'];
1052+
}
1053+
if (isset($yamlData['limits']['validation_passes'])) {
1054+
$yamlProblemProperties['multipassLimit'] = $yamlData['limits']['validation_passes'];
1055+
}
1056+
}
1057+
1058+
foreach ($yamlProblemProperties as $key => $value) {
1059+
try {
1060+
$propertyAccessor->setValue($problem, $key, $value);
1061+
} catch (Exception $e) {
1062+
$messages['danger'][] = sprintf('Error: problem.%s: %s', $key, $e->getMessage());
1063+
return false;
1064+
}
1065+
}
1066+
1067+
return true;
1068+
}
10501069
}

webapp/tests/Unit/Controller/Jury/ExecutableControllerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class ExecutableControllerTest extends JuryControllerTestCase
1111
protected static ?string $editDefault = null;
1212

1313
protected static string $baseUrl = '/jury/executables';
14-
protected static array $exampleEntries = ['adb', 'run', 'output validator for boolfind'];
14+
protected static array $exampleEntries = ['adb', 'run', 'output validator for Boolean'];
1515
protected static string $shortTag = 'executable';
1616
protected static array $deleteEntities = ['adb','default run script','rb','default full debug script'];
1717
protected static string $deleteEntityIdentifier = 'description';

0 commit comments

Comments
 (0)