konnektoren_core/challenges/package/
package_impl.rs

1use crate::{challenges::Custom, prelude::ChallengeConfig};
2
3use super::package_metadata::PackageMetadata;
4use std::collections::HashMap;
5
6#[derive(Debug, PartialEq, Clone)]
7pub struct Package {
8    pub metadata: PackageMetadata,
9    pub files: HashMap<String, Vec<u8>>,
10}
11
12impl Package {
13    pub fn new(metadata: PackageMetadata) -> Self {
14        Self {
15            metadata,
16            files: HashMap::new(),
17        }
18    }
19
20    pub fn add_file(&mut self, path: String, content: Vec<u8>) {
21        self.files.insert(path, content);
22    }
23
24    pub fn get_file(&self, path: &str) -> Option<&Vec<u8>> {
25        self.files.get(path)
26    }
27
28    pub fn get_file_as_string(&self, path: &str) -> Option<String> {
29        self.files
30            .get(path)
31            .map(|v| String::from_utf8_lossy(v).to_string())
32    }
33
34    /// Get the challenge configuration config.yml from the package
35    pub fn get_challenge_config(&self) -> Option<ChallengeConfig> {
36        Some(self.metadata.config.clone())
37    }
38
39    pub fn get_custom_challenge(&self) -> Option<Custom> {
40        Some(self.metadata.custom.clone())
41    }
42
43    pub fn get_html_file(&self) -> Option<String> {
44        let custom_challenge = self.get_custom_challenge()?;
45        let filename = custom_challenge.html;
46        self.get_file_as_string(&filename)
47    }
48
49    pub fn get_css_file(&self) -> Option<String> {
50        let custom_challenge = self.get_custom_challenge()?;
51        let filename = custom_challenge.css;
52        self.get_file_as_string(&filename)
53    }
54
55    pub fn get_js_file(&self) -> Option<String> {
56        let custom_challenge = self.get_custom_challenge()?;
57        let filename = custom_challenge.js;
58        self.get_file_as_string(&filename)
59    }
60
61    pub fn get_results_file(&self) -> Option<String> {
62        let custom_challenge = self.get_custom_challenge()?;
63        let filename = custom_challenge.results_html;
64        match filename {
65            Some(filename) => self.get_file_as_string(&filename),
66            None => None,
67        }
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74    use crate::challenges::Custom;
75
76    #[test]
77    fn test_package() {
78        let metadata = PackageMetadata::default();
79        let mut package = Package::new(metadata);
80        package.add_file("test.txt".to_string(), b"test".to_vec());
81        assert_eq!(package.get_file("test.txt"), Some(&b"test".to_vec()));
82        assert_eq!(
83            package.get_file_as_string("test.txt"),
84            Some("test".to_string())
85        );
86    }
87
88    #[test]
89    fn test_challenge_config() {
90        let mut metadata = PackageMetadata::default();
91        let config = ChallengeConfig {
92            tasks: 3.into(),
93            ..Default::default()
94        };
95        metadata.config = config.clone();
96        let mut package = Package::new(metadata);
97
98        package.add_file(
99            "config.yml".to_string(),
100            serde_yaml::to_string(&config).unwrap().into_bytes(),
101        );
102        assert_eq!(
103            package.get_challenge_config(),
104            Some(ChallengeConfig {
105                tasks: 3.into(),
106                ..Default::default()
107            })
108        );
109    }
110
111    #[test]
112    fn test_custom_challenge() {
113        let mut metadata = PackageMetadata::default();
114        let custom = Custom {
115            id: "custom_challenge".to_string(),
116            name: "Custom Challenge".to_string(),
117            description: "This is a custom challenge".to_string(),
118            ..Default::default()
119        };
120        metadata.custom = custom.clone();
121        let mut package = Package::new(metadata);
122
123        package.add_file(
124            "challenge.yml".to_string(),
125            serde_yaml::to_string(&custom).unwrap().into_bytes(),
126        );
127        assert_eq!(
128            package.get_custom_challenge(),
129            Some(Custom {
130                id: "custom_challenge".to_string(),
131                name: "Custom Challenge".to_string(),
132                description: "This is a custom challenge".to_string(),
133                ..Default::default()
134            })
135        );
136    }
137
138    #[test]
139    fn test_html_file() {
140        let mut metadata = PackageMetadata::default();
141        let custom = Custom {
142            id: "custom_challenge".to_string(),
143            name: "Custom Challenge".to_string(),
144            description: "This is a custom challenge".to_string(),
145            html: "index.html".to_string(),
146            ..Default::default()
147        };
148        metadata.custom = custom.clone();
149        let mut package = Package::new(metadata);
150
151        package.add_file(
152            "challenge.yml".to_string(),
153            serde_yaml::to_string(&custom).unwrap().into_bytes(),
154        );
155        package.add_file("index.html".to_string(), b"<html></html>".to_vec());
156        assert_eq!(package.get_html_file(), Some("<html></html>".to_string()));
157    }
158
159    #[test]
160    fn test_css_file() {
161        let mut metadata = PackageMetadata::default();
162        let custom = Custom {
163            id: "custom_challenge".to_string(),
164            name: "Custom Challenge".to_string(),
165            description: "This is a custom challenge".to_string(),
166            css: "style.css".to_string(),
167            ..Default::default()
168        };
169        metadata.custom = custom.clone();
170        let mut package = Package::new(metadata);
171
172        package.add_file(
173            "challenge.yml".to_string(),
174            serde_yaml::to_string(&custom).unwrap().into_bytes(),
175        );
176        package.add_file("style.css".to_string(), b"body { color: red; }".to_vec());
177        assert_eq!(
178            package.get_css_file(),
179            Some("body { color: red; }".to_string())
180        );
181    }
182
183    #[test]
184    fn test_js_file() {
185        let mut metadata = PackageMetadata::default();
186        let custom = Custom {
187            id: "custom_challenge".to_string(),
188            name: "Custom Challenge".to_string(),
189            description: "This is a custom challenge".to_string(),
190            js: "script.js".to_string(),
191            ..Default::default()
192        };
193        metadata.custom = custom.clone();
194        let mut package = Package::new(metadata);
195
196        package.add_file(
197            "challenge.yml".to_string(),
198            serde_yaml::to_string(&custom).unwrap().into_bytes(),
199        );
200        package.add_file(
201            "script.js".to_string(),
202            b"console.log('Hello, World!');".to_vec(),
203        );
204        assert_eq!(
205            package.get_js_file(),
206            Some("console.log('Hello, World!');".to_string())
207        );
208    }
209
210    #[test]
211    fn test_results_file() {
212        let mut metadata = PackageMetadata::default();
213        let custom = Custom {
214            id: "custom_challenge".to_string(),
215            name: "Custom Challenge".to_string(),
216            description: "This is a custom challenge".to_string(),
217            results_html: Some("results.html".to_string()),
218            ..Default::default()
219        };
220        metadata.custom = custom.clone();
221        let mut package = Package::new(metadata);
222
223        package.add_file(
224            "challenge.yml".to_string(),
225            serde_yaml::to_string(&custom).unwrap().into_bytes(),
226        );
227        package.add_file("results.html".to_string(), b"<html></html>".to_vec());
228        assert_eq!(
229            package.get_results_file(),
230            Some("<html></html>".to_string())
231        );
232    }
233}