grading
Version:
Grading of student submissions, in particular programming tests.
133 lines (122 loc) • 3.4 kB
text/typescript
import { PathLike } from "fs";
import { parseJsonWithComments } from "../cli/cliUtil";
export async function readGradingSchema(schemaFile: PathLike) {
const gradingSchema: GradingSchema = await parseJsonWithComments(schemaFile);
// post processing
gradingSchema.tasks.forEach(task => {
if (!task.grading) {
task.grading = [];
}
});
return gradingSchema;
}
export interface GradingSchema {
/** Only for VSCode,
* @see MANUAL_CORRECTIONS_SCHEMA_URL
*/
$schema: string
course: string,
term: string,
exam: string;
points: number;
minCoverageStatements?: number;
penaltiesCoverageMax?: number;
extraCoverageMax?: number;
/**
* Optional, if tests of penalties fail points are subtracted (well,
* actually added but the penalty points are expected to be negative).
*
* If the penalties have a precondition, the penalty is ignored if the precondition fails.
*
* Output is usually only generated if a penalty test fails.
* Otherwise it is not visible in the report later on.
*/
penalties?: Grading[];
tasks: Task[];
}
export interface Task {
name: string;
suite?: string;
skipHint?: string;
points: number;
preconditions?: Precondition[];
grading: Grading[];
manual: boolean;
/* Deprecated, use images instead */
image?: Image;
images?: Image[];
/**
* Optional, if tests of penalties fail points are subtracted (well,
* actually added but the penalty points are expected to be negative).
*
* If the penalties have a precondition, the penalty is ignored if the precondition fails.
*
* Output is usually only generated if a penalty test fails.
* Otherwise it is not visible in the report later on.
*/
penalties?: Grading[];
}
export interface Image {
src: string;
text: string;
missing?: string
width?: string
}
/**
* Bewertung (or Penalty)
*/
export interface Grading {
suite?: string;
tests: string[];
isBonus?: boolean;
/**
* Points, equally divided for each test.
* If the Bewertung is a penalty, the points are expected to be negative.
*/
points: number;
/**
* If the precondition fails, no further tests are analyzed.
* If the Bewertung is positive, 0 points are given.
* If the Bewertung is a penalty, 0 points are subtracted as well.
*/
preconditions?: Precondition[];
/**
* Do not access this property directly, instead
* use {@link gradingText}.
*/
text?: string;
/**
* Deprecated, use images instead
*/
image?: Image;
images?: Image[];
}
/**
* If not provided, text of first test is used.
*/
export function gradingText(grading: Grading) {
if (grading.text) {
return grading.text;
}
if (grading.tests.length > 0) {
return grading.tests[0];
}
throw new Error("Grading does not define any tests (and no text).")
}
export interface Precondition {
test: string;
/**
* Use preconditionText instead
*/
failure?: string;
suite?: string;
}
/**
* If not provided, text of first test is used.
*/
export function preconditionText(precondition: Precondition) {
if (precondition.failure) {
return precondition.failure;
}
return precondition.test;
}