mirror of
https://github.com/renbaoshuo/S2OJ.git
synced 2024-09-08 01:45:18 +00:00
feat(remote_judger/loj): judge details
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
72242edbfc
commit
cea0e82db8
@ -5,6 +5,7 @@ import sleep from '../utils/sleep';
|
||||
import { IBasicProvider, RemoteAccount, USER_AGENT } from '../interface';
|
||||
import Logger from '../utils/logger';
|
||||
import { normalize, VERDICT } from '../verdict';
|
||||
import { crlf, LF } from 'crlf-normalize';
|
||||
|
||||
proxy(superagent);
|
||||
const logger = new Logger('remote/loj');
|
||||
@ -303,12 +304,149 @@ export default class LibreojProvider implements IBasicProvider {
|
||||
});
|
||||
}
|
||||
|
||||
const parse = (str: string) => crlf(str, LF);
|
||||
|
||||
const getSubtaskStatusDisplayText = (testcases: any): string => {
|
||||
let result: string = null;
|
||||
|
||||
for (const testcase of testcases) {
|
||||
if (!testcase.testcaseHash) {
|
||||
result = 'Skipped';
|
||||
|
||||
break;
|
||||
} else if (
|
||||
body.progress.testcaseResult[testcase.testcaseHash].status !==
|
||||
'Accepted'
|
||||
) {
|
||||
result = body.progress.testcaseResult[testcase.testcaseHash].status;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result ||= 'Accepted';
|
||||
result =
|
||||
VERDICT[
|
||||
Object.keys(VERDICT).find(k => normalize(result).includes(k))
|
||||
];
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const getTestcaseBlock = (id: string, index: number): string => {
|
||||
const testcase = body.progress.testcaseResult[id];
|
||||
|
||||
if (!testcase) return '';
|
||||
|
||||
const status =
|
||||
VERDICT[
|
||||
Object.keys(VERDICT).find(k =>
|
||||
normalize(testcase.status).includes(k)
|
||||
)
|
||||
];
|
||||
let test_info = '';
|
||||
|
||||
test_info += `<test num="${
|
||||
index + 1
|
||||
}" info="${status}" time="${Math.round(testcase.time || 0)}" memory="${
|
||||
testcase.memory
|
||||
}">`;
|
||||
|
||||
if (testcase.input) {
|
||||
if (typeof testcase.input === 'string') {
|
||||
test_info += `<in>${parse(testcase.input)}</in>\n`;
|
||||
} else {
|
||||
test_info += `<in>${parse(testcase.input.data)}\n\n(${
|
||||
testcase.input.omittedLength
|
||||
} bytes omitted)</in>\n`;
|
||||
}
|
||||
}
|
||||
|
||||
if (testcase.userOutput) {
|
||||
if (typeof testcase.userOutput === 'string') {
|
||||
test_info += `<out>${parse(testcase.userOutput)}</out>\n`;
|
||||
} else {
|
||||
test_info += `<out>${parse(testcase.userOutput.data)}\n\n(${
|
||||
testcase.userOutput.omittedLength
|
||||
} bytes omitted)</out>\n`;
|
||||
}
|
||||
}
|
||||
|
||||
if (testcase.output) {
|
||||
if (typeof testcase.output === 'string') {
|
||||
test_info += `<ans>${parse(testcase.output)}</ans>\n`;
|
||||
} else {
|
||||
test_info += `<ans>${parse(testcase.output.data)}\n\n(${
|
||||
testcase.output.omittedLength
|
||||
} bytes omitted)</ans>\n`;
|
||||
}
|
||||
}
|
||||
|
||||
if (testcase.checkerMessage) {
|
||||
if (typeof testcase.checkerMessage === 'string') {
|
||||
test_info += `<res>${parse(testcase.checkerMessage)}</res>\n`;
|
||||
} else {
|
||||
test_info += `<res>${parse(testcase.checkerMessage.data)}\n\n(${
|
||||
testcase.checkerMessage.omittedLength
|
||||
} bytes omitted)</res>\n`;
|
||||
}
|
||||
}
|
||||
|
||||
test_info += '</test>';
|
||||
|
||||
return test_info;
|
||||
};
|
||||
|
||||
let details = '';
|
||||
|
||||
details += `<info-block>REMOTE_SUBMISSION_ID = ${id}\nVERDICT = ${status}</info-block>`;
|
||||
|
||||
// Samples
|
||||
if (body.progress.samples) {
|
||||
details += `<subtask title="Samples" info="${getSubtaskStatusDisplayText(
|
||||
body.progress.samples
|
||||
)}" num="0">${body.progress.samples
|
||||
.map((item, index) =>
|
||||
item.testcaseHash
|
||||
? getTestcaseBlock(item.testcaseHash, index)
|
||||
: `<test num="${index + 1}" info="Skipped"></test>`
|
||||
)
|
||||
.join('\n')}</subtask>`;
|
||||
}
|
||||
|
||||
// Tests
|
||||
if (body.progress.subtasks.length === 1) {
|
||||
details += `<tests>${body.progress.subtasks[0].testcases
|
||||
.map((item, index) =>
|
||||
item.testcaseHash
|
||||
? getTestcaseBlock(item.testcaseHash, index)
|
||||
: `<test num="${index + 1}" info="Skipped"></test>`
|
||||
)
|
||||
.join('\n')}</tests>`;
|
||||
} else {
|
||||
details += `<tests>${body.progress.subtasks
|
||||
.map(
|
||||
(subtask, index) =>
|
||||
`<subtask num="${index + 1}" info="${getSubtaskStatusDisplayText(
|
||||
subtask.testcases
|
||||
)}">${subtask.testcases
|
||||
.map((item, index) =>
|
||||
item.testcaseHash
|
||||
? getTestcaseBlock(item.testcaseHash, index)
|
||||
: `<test num="${index + 1}" info="Skipped"></test>`
|
||||
)
|
||||
.join('\n')}</subtask>`
|
||||
)
|
||||
.join('\n')}</tests>`;
|
||||
}
|
||||
|
||||
return await end({
|
||||
id,
|
||||
status: body.meta.status,
|
||||
score: body.meta.score,
|
||||
time: body.meta.timeUsed,
|
||||
memory: body.meta.memoryUsed,
|
||||
details: `<div>${details}</div>`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -465,6 +465,7 @@ class JudgmentDetailsPrinter {
|
||||
echo '</div>';
|
||||
} elseif ($node->nodeName == 'subtask') {
|
||||
$subtask_info = $node->getAttribute('info');
|
||||
$subtask_title = $node->getAttribute('title');
|
||||
$subtask_num = $node->getAttribute('num');
|
||||
$subtask_score = $node->getAttribute('score');
|
||||
$subtask_time = $this->_get_attr($node, 'time', -1);
|
||||
@ -482,7 +483,11 @@ class JudgmentDetailsPrinter {
|
||||
|
||||
echo '<div class="row">';
|
||||
echo '<div class="col-sm-4">';
|
||||
echo '<h3 class="fs-5">', 'Subtask #', $subtask_num, ': ', '</h3>';
|
||||
if ($subtask_title !== '') {
|
||||
echo '<h3 class="fs-5">', $subtask_title, ': ', '</h3>';
|
||||
} else {
|
||||
echo '<h3 class="fs-5">', 'Subtask #', $subtask_num, ': ', '</h3>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
if ($this->styler->show_score && $subtask_score !== '') {
|
||||
@ -494,7 +499,7 @@ class JudgmentDetailsPrinter {
|
||||
echo htmlspecialchars($subtask_info);
|
||||
echo '</div>';
|
||||
} else {
|
||||
echo '<div class="col-sm-4">';
|
||||
echo '<div class="col-sm-4 uoj-status-text">';
|
||||
echo $this->styler->getTestInfoIcon($subtask_info);
|
||||
echo htmlspecialchars($subtask_info);
|
||||
echo '</div>';
|
||||
@ -541,6 +546,9 @@ class JudgmentDetailsPrinter {
|
||||
$accordion_parent .= "_collapse_subtask_{$this->subtask_num}_accordion";
|
||||
}
|
||||
$accordion_collapse = "{$accordion_parent}_collapse_test_{$test_num}";
|
||||
if ($this->subtask_num != null) {
|
||||
$accordion_collapse .= "_in_subtask_{$this->subtask_num}";
|
||||
}
|
||||
if (!$this->styler->shouldFadeDetails($test_info)) {
|
||||
echo '<div class="card-header uoj-submission-result-item bg-transparent rounded-0 border-0" data-bs-toggle="collapse" data-bs-parent="#', $accordion_parent, '" data-bs-target="#', $accordion_collapse, '">';
|
||||
} else {
|
||||
@ -762,7 +770,7 @@ class SubmissionDetailsStyler {
|
||||
}
|
||||
}
|
||||
public function shouldFadeDetails($info) {
|
||||
return $this->fade_all_details || $info == 'Extra Test Passed';
|
||||
return $this->fade_all_details || $info == 'Extra Test Passed' || $info == 'Skipped';
|
||||
}
|
||||
}
|
||||
class CustomTestSubmissionDetailsStyler {
|
||||
|
Loading…
Reference in New Issue
Block a user