konnektoren_core/challenges/
challenge_result.rs1use crate::challenges::error::{ChallengeError, Result};
2use crate::challenges::{
3 ChallengeInput, ContextItemChoiceAnswers, CustomChallengeResult, GapFillAnswer,
4 MultipleChoiceOption, OrderingResult, SortTableRow,
5};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9pub enum ChallengeResult {
10 MultipleChoice(Vec<MultipleChoiceOption>),
11 ContextualChoice(Vec<ContextItemChoiceAnswers>),
12 GapFill(Vec<GapFillAnswer>),
13 SortTable(Vec<SortTableRow>),
14 Informative,
15 Ordering(Vec<OrderingResult>),
16 Custom(CustomChallengeResult),
17 Vocabulary,
18}
19
20impl Default for ChallengeResult {
21 fn default() -> Self {
22 ChallengeResult::MultipleChoice(Vec::new())
23 }
24}
25
26impl ChallengeResult {
27 pub fn add_input(&mut self, input: ChallengeInput) -> Result<()> {
28 match self {
29 ChallengeResult::MultipleChoice(options) => match input {
30 ChallengeInput::MultipleChoice(option) => {
31 options.push(option);
32 Ok(())
33 }
34 _ => Err(ChallengeError::InvalidInput(
35 "Expected MultipleChoice input".to_string(),
36 )),
37 },
38 ChallengeResult::ContextualChoice(answers) => match input {
39 ChallengeInput::ContextualChoice(answer) => {
40 answers.push(answer);
41 Ok(())
42 }
43 _ => Err(ChallengeError::InvalidInput(
44 "Expected ContextualChoice input".to_string(),
45 )),
46 },
47 ChallengeResult::GapFill(answers) => match input {
48 ChallengeInput::GapFill(answer) => {
49 answers.push(answer);
50 Ok(())
51 }
52 _ => Err(ChallengeError::InvalidInput(
53 "Expected GapFill input".to_string(),
54 )),
55 },
56 ChallengeResult::SortTable(rows) => match input {
57 ChallengeInput::SortTable(row) => {
58 rows.push(row);
59 Ok(())
60 }
61 _ => Err(ChallengeError::InvalidInput(
62 "Expected SortTable input".to_string(),
63 )),
64 },
65 ChallengeResult::Ordering(results) => match input {
66 ChallengeInput::Ordering(result) => {
67 results.push(result);
68 Ok(())
69 }
70 _ => Err(ChallengeError::InvalidInput(
71 "Expected Ordering input".to_string(),
72 )),
73 },
74 ChallengeResult::Informative => Ok(()),
75 ChallengeResult::Custom(_) => Ok(()),
76 ChallengeResult::Vocabulary => Ok(()),
77 }
78 }
79
80 pub fn set_input(&mut self, index: usize, input: ChallengeInput) -> Result<()> {
82 match self {
83 ChallengeResult::MultipleChoice(options) => match input {
84 ChallengeInput::MultipleChoice(option) => {
85 while options.len() <= index {
87 options.push(MultipleChoiceOption {
88 id: 0,
89 name: String::new(),
90 });
91 }
92 options[index] = option;
93 Ok(())
94 }
95 _ => Err(ChallengeError::InvalidInput(
96 "Expected MultipleChoice input".to_string(),
97 )),
98 },
99 ChallengeResult::ContextualChoice(answers) => match input {
100 ChallengeInput::ContextualChoice(answer) => {
101 while answers.len() <= index {
102 answers.push(ContextItemChoiceAnswers { ids: vec![] });
103 }
104 answers[index] = answer;
105 Ok(())
106 }
107 _ => Err(ChallengeError::InvalidInput(
108 "Expected ContextualChoice input".to_string(),
109 )),
110 },
111 ChallengeResult::GapFill(answers) => match input {
112 ChallengeInput::GapFill(answer) => {
113 while answers.len() <= index {
114 answers.push(GapFillAnswer {
115 question_index: 0,
116 answers: vec![],
117 });
118 }
119 answers[index] = answer;
120 Ok(())
121 }
122 _ => Err(ChallengeError::InvalidInput(
123 "Expected GapFill input".to_string(),
124 )),
125 },
126 ChallengeResult::SortTable(rows) => match input {
127 ChallengeInput::SortTable(row) => {
128 while rows.len() <= index {
129 rows.push(SortTableRow {
130 id: 0,
131 values: vec![],
132 });
133 }
134 rows[index] = row;
135 Ok(())
136 }
137 _ => Err(ChallengeError::InvalidInput(
138 "Expected SortTable input".to_string(),
139 )),
140 },
141 ChallengeResult::Ordering(results) => match input {
142 ChallengeInput::Ordering(result) => {
143 while results.len() <= index {
144 results.push(OrderingResult { order: vec![] });
145 }
146 results[index] = result;
147 Ok(())
148 }
149 _ => Err(ChallengeError::InvalidInput(
150 "Expected Ordering input".to_string(),
151 )),
152 },
153 ChallengeResult::Informative => Ok(()),
154 ChallengeResult::Custom(_) => Ok(()),
155 ChallengeResult::Vocabulary => Ok(()),
156 }
157 }
158
159 pub fn len(&self) -> usize {
160 match self {
161 ChallengeResult::MultipleChoice(options) => options.len(),
162 ChallengeResult::ContextualChoice(items) => items.len(),
163 ChallengeResult::GapFill(answers) => answers.len(),
164 ChallengeResult::SortTable(rows) => rows.len(),
165 ChallengeResult::Ordering(results) => results.len(),
166 ChallengeResult::Informative => 0,
167 ChallengeResult::Custom(_) => 0,
168 ChallengeResult::Vocabulary => 0,
169 }
170 }
171
172 pub fn is_empty(&self) -> bool {
173 match self {
174 ChallengeResult::MultipleChoice(options) => options.is_empty(),
175 ChallengeResult::ContextualChoice(items) => items.is_empty(),
176 ChallengeResult::GapFill(answers) => answers.is_empty(),
177 ChallengeResult::SortTable(rows) => rows.is_empty(),
178 ChallengeResult::Ordering(results) => results.is_empty(),
179 ChallengeResult::Informative => true,
180 ChallengeResult::Custom(_) => true,
181 ChallengeResult::Vocabulary => true,
182 }
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn default_challenge_result() {
192 let challenge_result = ChallengeResult::default();
193 match challenge_result {
194 ChallengeResult::MultipleChoice(options) => {
195 assert!(options.is_empty());
196 }
197 _ => panic!("Invalid challenge result"),
198 }
199 }
200
201 #[test]
202 fn add_multiple_choice() {
203 let mut challenge_result = ChallengeResult::default();
204 let input = ChallengeInput::MultipleChoice(MultipleChoiceOption {
205 id: 1,
206 name: "Option 1".to_string(),
207 });
208 let result = challenge_result.add_input(input);
209 assert!(result.is_ok());
210 match challenge_result {
211 ChallengeResult::MultipleChoice(options) => {
212 assert_eq!(options.len(), 1);
213 }
214 _ => panic!("Invalid challenge result"),
215 }
216 }
217
218 #[test]
219 fn add_sort_table() {
220 let mut challenge_result = ChallengeResult::SortTable(Vec::new());
221 let input = ChallengeInput::SortTable(SortTableRow {
222 id: 1,
223 values: vec!["Value 1".to_string()],
224 });
225 let result = challenge_result.add_input(input);
226 assert!(result.is_ok());
227 match challenge_result {
228 ChallengeResult::SortTable(rows) => {
229 assert_eq!(rows.len(), 1);
230 }
231 _ => panic!("Invalid challenge result"),
232 }
233 }
234
235 #[test]
236 fn test_is_empty() {
237 let challenge_result = ChallengeResult::default();
238 assert!(challenge_result.is_empty());
239 }
240
241 #[test]
242 fn test_len() {
243 let challenge_result = ChallengeResult::MultipleChoice(vec![
244 MultipleChoiceOption {
245 id: 1,
246 name: "Option 1".to_string(),
247 },
248 MultipleChoiceOption {
249 id: 2,
250 name: "Option 2".to_string(),
251 },
252 ]);
253 assert_eq!(challenge_result.len(), 2);
254 }
255
256 #[test]
257 fn add_ordering() {
258 let mut challenge_result = ChallengeResult::Ordering(Vec::new());
259 let input = ChallengeInput::Ordering(OrderingResult {
260 order: vec![2, 0, 1],
261 });
262 let result = challenge_result.add_input(input);
263 assert!(result.is_ok());
264 match challenge_result {
265 ChallengeResult::Ordering(results) => {
266 assert_eq!(results.len(), 1);
267 assert_eq!(results[0].order, vec![2, 0, 1]);
268 }
269 _ => panic!("Invalid challenge result"),
270 }
271 }
272
273 #[test]
274 fn test_ordering_len() {
275 let challenge_result = ChallengeResult::Ordering(vec![
276 OrderingResult {
277 order: vec![0, 1, 2],
278 },
279 OrderingResult {
280 order: vec![2, 1, 0],
281 },
282 ]);
283 assert_eq!(challenge_result.len(), 2);
284 }
285
286 #[test]
287 fn test_ordering_is_empty() {
288 let challenge_result = ChallengeResult::Ordering(Vec::new());
289 assert!(challenge_result.is_empty());
290 }
291
292 #[test]
293 fn test_add_input_wrong_type() {
294 let mut result = ChallengeResult::MultipleChoice(vec![]);
295 let input = ChallengeInput::SortTable(SortTableRow::default());
296 let err = result.add_input(input);
297 assert!(err.is_err());
298 }
299
300 #[test]
301 fn test_set_input_multiple_choice() {
302 let mut challenge_result = ChallengeResult::default();
303 let input = ChallengeInput::MultipleChoice(MultipleChoiceOption {
304 id: 2,
305 name: "Option 2".to_string(),
306 });
307
308 let result = challenge_result.set_input(2, input);
310 assert!(result.is_ok());
311
312 match challenge_result {
313 ChallengeResult::MultipleChoice(options) => {
314 assert_eq!(options.len(), 3);
315 assert_eq!(options[0].id, 0); assert_eq!(options[1].id, 0); assert_eq!(options[2].id, 2); assert_eq!(options[2].name, "Option 2");
319 }
320 _ => panic!("Invalid challenge result"),
321 }
322 }
323
324 #[test]
325 fn test_set_input_replace_existing() {
326 let mut challenge_result = ChallengeResult::MultipleChoice(vec![
327 MultipleChoiceOption {
328 id: 1,
329 name: "Option 1".to_string(),
330 },
331 MultipleChoiceOption {
332 id: 2,
333 name: "Option 2".to_string(),
334 },
335 ]);
336
337 let new_input = ChallengeInput::MultipleChoice(MultipleChoiceOption {
338 id: 3,
339 name: "Option 3".to_string(),
340 });
341
342 let result = challenge_result.set_input(1, new_input);
344 assert!(result.is_ok());
345
346 match challenge_result {
347 ChallengeResult::MultipleChoice(options) => {
348 assert_eq!(options.len(), 2);
349 assert_eq!(options[0].id, 1); assert_eq!(options[1].id, 3); assert_eq!(options[1].name, "Option 3");
352 }
353 _ => panic!("Invalid challenge result"),
354 }
355 }
356
357 #[test]
358 fn test_set_input_wrong_type() {
359 let mut result = ChallengeResult::MultipleChoice(vec![]);
360 let input = ChallengeInput::SortTable(SortTableRow::default());
361 let err = result.set_input(0, input);
362 assert!(err.is_err());
363 }
364
365 #[test]
366 fn test_set_input_ordering() {
367 let mut challenge_result = ChallengeResult::Ordering(Vec::new());
368 let input = ChallengeInput::Ordering(OrderingResult {
369 order: vec![2, 0, 1],
370 });
371
372 let result = challenge_result.set_input(1, input);
373 assert!(result.is_ok());
374
375 match challenge_result {
376 ChallengeResult::Ordering(results) => {
377 assert_eq!(results.len(), 2);
378 assert!(results[0].order.is_empty()); assert_eq!(results[1].order, vec![2, 0, 1]);
380 }
381 _ => panic!("Invalid challenge result"),
382 }
383 }
384
385 #[test]
386 fn test_set_input_contextual_choice() {
387 let mut result = ChallengeResult::ContextualChoice(Vec::new());
388 let input = ChallengeInput::ContextualChoice(ContextItemChoiceAnswers { ids: vec![0, 1] });
389
390 let res = result.set_input(0, input);
391 assert!(res.is_ok());
392
393 match result {
394 ChallengeResult::ContextualChoice(answers) => {
395 assert_eq!(answers.len(), 1);
396 assert_eq!(answers[0].ids, vec![0, 1]);
397 }
398 _ => panic!("Expected ContextualChoice result"),
399 }
400 }
401
402 #[test]
403 fn test_set_input_fills_gaps_contextual_choice() {
404 let mut result = ChallengeResult::ContextualChoice(Vec::new());
405 let input = ChallengeInput::ContextualChoice(ContextItemChoiceAnswers { ids: vec![2] });
406
407 let res = result.set_input(2, input);
409 assert!(res.is_ok());
410
411 match result {
412 ChallengeResult::ContextualChoice(answers) => {
413 assert_eq!(answers.len(), 3);
414 assert!(answers[0].ids.is_empty()); assert!(answers[1].ids.is_empty()); assert_eq!(answers[2].ids, vec![2]);
417 }
418 _ => panic!("Expected ContextualChoice result"),
419 }
420 }
421
422 #[test]
423 fn test_set_input_wrong_type_contextual_choice() {
424 let mut result = ChallengeResult::ContextualChoice(Vec::new());
425 let input = ChallengeInput::MultipleChoice(MultipleChoiceOption::default());
426
427 let res = result.set_input(0, input);
428 assert!(res.is_err());
429 assert!(matches!(res.unwrap_err(), ChallengeError::InvalidInput(_)));
430 }
431}