konnektoren_core/challenges/
challenge_factory.rs

1use crate::challenges::Base64Serializable;
2use crate::challenges::challenge::Challenge;
3use crate::challenges::challenge_config::ChallengeConfig;
4use crate::challenges::challenge_type::ChallengeType;
5use crate::challenges::error::{ChallengeError, Result};
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
9pub struct ChallengeFactory {
10    pub challenge_types: Vec<ChallengeType>,
11}
12
13impl Default for ChallengeFactory {
14    fn default() -> Self {
15        ChallengeFactory {
16            challenge_types: vec![
17                ChallengeType::default(),
18                serde_yaml::from_str(include_str!("../../assets/articles-1.yml")).unwrap(),
19                serde_yaml::from_str(include_str!("../../assets/past-tense.yml")).unwrap(),
20                serde_yaml::from_str(include_str!("../../assets/sentence_structure.yml")).unwrap(),
21            ],
22        }
23    }
24}
25
26impl ChallengeFactory {
27    pub fn new() -> Self {
28        ChallengeFactory {
29            challenge_types: vec![],
30        }
31    }
32
33    pub fn create_challenge(&self, challenge_config: &ChallengeConfig) -> Result<Challenge> {
34        let challenge_type = self
35            .challenge_types
36            .iter()
37            .find(|challenge_type| challenge_type.id() == challenge_config.challenge)
38            .ok_or(ChallengeError::ChallengeTypeNotFound)?;
39        Ok(Challenge::new(
40            &challenge_type.of_tasks(&challenge_config.tasks),
41            challenge_config,
42        ))
43    }
44
45    pub fn add_challenge_from_base64(&mut self, base64_data: &str) -> Result<()> {
46        let challenge_type = ChallengeType::from_base64(base64_data)?;
47        self.challenge_types.push(challenge_type);
48        Ok(())
49    }
50
51    pub fn export_challenge_to_base64(&self, challenge_id: &str) -> Result<String> {
52        let challenge_type = self
53            .challenge_types
54            .iter()
55            .find(|ct| ct.id() == challenge_id)
56            .ok_or_else(|| ChallengeError::ChallengeNotFound(challenge_id.to_string()))?;
57
58        challenge_type.to_base64()
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn create_challenge() {
68        let mut challenge_factory = ChallengeFactory::new();
69        let challenge_type = ChallengeType::default();
70        challenge_factory.challenge_types.push(challenge_type);
71        let challenge_config = ChallengeConfig {
72            challenge: "konnektoren".to_string(),
73            tasks: 2.into(),
74            ..Default::default()
75        };
76
77        let challenge = challenge_factory.create_challenge(&challenge_config);
78        match challenge.unwrap().challenge_type {
79            ChallengeType::MultipleChoice(dataset) => {
80                assert_eq!(dataset.questions.len(), 2);
81            }
82            _ => panic!("Invalid challenge type"),
83        }
84    }
85
86    #[test]
87    fn test_add_challenge_from_base64() {
88        let mut factory = ChallengeFactory::new();
89        let original_challenge = ChallengeType::default();
90
91        // Export to base64
92        let base64_data = original_challenge.to_base64().unwrap();
93
94        // Import from base64
95        factory.add_challenge_from_base64(&base64_data).unwrap();
96
97        assert_eq!(factory.challenge_types.len(), 1);
98        assert_eq!(factory.challenge_types[0].id(), original_challenge.id());
99    }
100
101    #[test]
102    fn test_export_challenge_to_base64() {
103        let factory = ChallengeFactory::default();
104        let base64_data = factory.export_challenge_to_base64("konnektoren").unwrap();
105        assert!(!base64_data.is_empty());
106    }
107}