tmc_langs_framework/
domain.rs

1//! Contains structs that model data related to exercises.
2
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use std::{
6    collections::{HashMap, HashSet},
7    path::PathBuf,
8};
9
10/// A description of an exercise's test case.
11#[derive(Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash)]
12#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
13pub struct TestDesc {
14    /// The full name of the test.
15    ///
16    /// If the language organises tests into suites or classes, it is customary
17    /// to name the test as "class_name.method_name".
18    pub name: String,
19    /// The list of point names that passing this test may give.
20    ///
21    /// To obtain a point X, the user must pass all exercises that require point X.
22    pub points: Vec<String>,
23}
24
25impl TestDesc {
26    pub fn new(name: String, points: Vec<String>) -> Self {
27        Self { name, points }
28    }
29}
30
31/// The result of a single test case.
32#[derive(Debug, Deserialize, Serialize, JsonSchema)]
33#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
34pub struct TestResult {
35    pub name: String,
36    pub successful: bool,
37    /// List of points that were received from the exercise from passed tests.
38    pub points: Vec<String>,
39    pub message: String,
40    #[serde(default)]
41    pub exception: Vec<String>,
42}
43
44/// A description of an exercise.
45#[derive(Debug, Deserialize, Serialize, JsonSchema)]
46#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
47pub struct ExerciseDesc {
48    /// The name of the exercise to be shown to the user.
49    /// Does not necessarily match or even contain the directory name.
50    pub name: String,
51    /// Descriptions of the tests that will be run for this exercise.
52    pub tests: Vec<TestDesc>,
53}
54
55impl ExerciseDesc {
56    pub fn new(name: String, tests: Vec<TestDesc>) -> Self {
57        Self { name, tests }
58    }
59}
60
61/// The result of running an exercise's test suite against a submission.
62#[derive(Debug, Deserialize, Serialize, JsonSchema)]
63#[serde(rename_all = "camelCase")]
64#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
65pub struct RunResult {
66    /// The overall status of a test run.
67    pub status: RunStatus,
68    /// Whether each test passed and which points were awarded.
69    pub test_results: Vec<TestResult>,
70    /// Logs from the test run.
71    /// The key may be an arbitrary string identifying the type of log.
72    pub logs: HashMap<String, String>,
73}
74
75impl RunResult {
76    pub fn new(
77        status: RunStatus,
78        test_results: Vec<TestResult>,
79        logs: HashMap<String, String>,
80    ) -> Self {
81        Self {
82            status,
83            test_results,
84            logs,
85        }
86    }
87}
88
89/// The overall status of a test run.
90#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
91#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
92#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
93pub enum RunStatus {
94    /// The submission and tests compiled and all tests passed.
95    Passed,
96    /// The submission and tests compiled but some tests failed.
97    TestsFailed,
98    /// The submission or tests did not compile.
99    // TODO: "The compiler error should be given in {@code logs[SpecialLogs.COMPILER_OUTPUT]}."
100    CompileFailed,
101    /// The submission compiled but testrun was interrupted.
102    TestrunInterrupted,
103    /// For when no other status seems suitable, or the language plugin has
104    /// suffered an internal error.
105    // TODO: "Details should be given in {@code logs[SpecialLogs.GENERIC_ERROR_MESSAGE]}.""
106    GenericError,
107}
108
109/// Represents configuration based on which submission may be packaged.
110#[derive(Debug, Deserialize, Serialize, JsonSchema)]
111#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
112pub struct ExercisePackagingConfiguration {
113    /// Student folders or files which are copied from submission.
114    pub student_file_paths: HashSet<PathBuf>,
115    /// Exercise folders or files which are copied from exercise template or clone.
116    pub exercise_file_paths: HashSet<PathBuf>,
117}
118
119impl ExercisePackagingConfiguration {
120    pub fn new(
121        student_file_paths: HashSet<PathBuf>,
122        exercise_file_paths: HashSet<PathBuf>,
123    ) -> Self {
124        Self {
125            student_file_paths,
126            exercise_file_paths,
127        }
128    }
129}
130
131/// Determines how style errors are handled.
132#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
133#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
134#[serde(rename_all = "UPPERCASE")]
135pub enum StyleValidationStrategy {
136    Fail,
137    Warn,
138    Disabled,
139}
140
141/// A style validation error.
142#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
143#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
144pub struct StyleValidationError {
145    pub column: u32,
146    pub line: u32,
147    pub message: String,
148    pub source_name: String,
149}
150
151/// The result of a style check.
152#[derive(Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
153#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
154pub struct StyleValidationResult {
155    pub strategy: StyleValidationStrategy,
156    pub validation_errors: Option<HashMap<PathBuf, Vec<StyleValidationError>>>,
157}