grading
Version:
Grading of student submissions, in particular programming tests.
85 lines (69 loc) • 2.63 kB
text/typescript
import { Submitter } from "../cli/submitter";
import { GRADING_SCHEMA_URL } from "../constants";
import { Grading, GradingSchema, Task } from "./gradingschema";
import { loadUnitReport } from "./reportLoader";
export async function generateGradingSchema(reportsDir: string, submitter: Submitter) {
const unitCheck = await loadUnitReport(reportsDir, submitter.submissionId, "check");
if (!unitCheck) {
program.error(`No unit check report with ID ${submitter.submissionId} found in ${reportsDir}, cannot generate schema`);
}
const gradingSchema: GradingSchema = {
$schema: GRADING_SCHEMA_URL,
course: "Generated",
term: "WS/SS",
exam: "Exam",
points: 100,
tasks: []
}
gradingSchema.term = computeTerm();
const testSuites = unitCheck.testsuite instanceof Array ? unitCheck.testsuite : [unitCheck.testsuite];
const pointsPerTask = Math.round(100 / testSuites.length);
let totalPoints = 0;
for (let counter = 0; counter < testSuites.length; counter++) {
const testSuite = testSuites[counter];
const task: Task = {
name: computeNameFromSuite(testSuite.name, counter),
suite: testSuite.name,
points: counter < testSuites.length - 1 ? pointsPerTask : 100 - totalPoints,
grading: [],
manual: false
}
gradingSchema.tasks.push(task);
totalPoints += task.points;
const testCases = testSuite.testcase;
const grading: Grading = {
points: task.points,
text: `Generated from test suite ${testSuite.name} with ${testCases.length} test cases.`,
tests: testCases.map(testCase=>testCase.name)
}
task.grading.push(grading);
}
return gradingSchema;
}
function computeTerm() {
const now = new Date();
const month = now.getMonth();
let year = now.getFullYear();
const term = month < 3 || month>9 ? "WS" : "SS";
if (term==='WS') {
if (month < 3) year--;
return term + " " + year + "/" + ((year+1)%2000);
} else {
return term + " " + year;
}
}
function computeNameFromSuite(name: string, counter: number): string {
if (!name) {
return "Task " + (1 + counter);
}
const parts = name.split(".");
for (let i = parts.length-1; i >= 0; i--) {
if ( ["ts", "js", "test", "check", "spec", "jsx", "tsx"].includes(parts[i])) {
parts.splice(i, 1);
}
}
if (parts.length > 0) {
return parts.join(" ");
}
return parts[0] ?? ("Task " + (1 + counter));
}