konnektoren_core/events/
parse.rs1use super::EventParseError;
2use super::{ChallengeEvent, Event, GameEvent};
3use serde_json::Value;
4use wasm_bindgen::prelude::*;
5
6impl From<EventParseError> for JsValue {
7 fn from(error: EventParseError) -> Self {
8 JsValue::from_str(&error.to_string())
9 }
10}
11
12impl TryFrom<JsValue> for Event {
13 type Error = EventParseError;
14
15 fn try_from(value: JsValue) -> Result<Self, Self::Error> {
16 let obj: Value = serde_wasm_bindgen::from_value(value)
17 .map_err(|e| EventParseError::ParseError(e.to_string()))?;
18 Event::try_from(obj)
19 }
20}
21
22impl TryFrom<Value> for Event {
23 type Error = EventParseError;
24
25 fn try_from(obj: Value) -> Result<Self, Self::Error> {
26 match obj.get("type").and_then(|v| v.as_str()) {
27 Some("Game") => Ok(Event::Game(GameEvent::try_from(obj)?)),
28 Some("Challenge") => Ok(Event::Challenge(ChallengeEvent::try_from(obj)?)),
29 Some(unknown_type) => Err(EventParseError::UnknownEventType(unknown_type.to_string())),
30 None => Err(EventParseError::MissingData),
31 }
32 }
33}
34
35impl TryFrom<Value> for GameEvent {
36 type Error = EventParseError;
37
38 fn try_from(value: Value) -> Result<Self, Self::Error> {
39 match value.get("action").and_then(|v| v.as_str()) {
40 Some("Started") => Ok(GameEvent::Started),
41 Some(unknown_action) => Err(EventParseError::UnknownEventType(
42 unknown_action.to_string(),
43 )),
44 None => Err(EventParseError::MissingData),
45 }
46 }
47}
48
49impl TryFrom<Value> for ChallengeEvent {
50 type Error = EventParseError;
51
52 fn try_from(value: Value) -> Result<Self, EventParseError> {
53 match value.get("action").and_then(|v| v.as_str()) {
54 Some("SolvedCorrect") => {
55 let index = value
56 .get("index")
57 .ok_or(EventParseError::MissingData)?
58 .as_u64()
59 .ok_or_else(|| {
60 EventParseError::InvalidData("index must be a number".to_string())
61 })?;
62 Ok(ChallengeEvent::SolvedCorrect(index as usize))
63 }
64 Some("SolvedIncorrect") => {
65 let index = value
66 .get("index")
67 .ok_or(EventParseError::MissingData)?
68 .as_u64()
69 .ok_or_else(|| {
70 EventParseError::InvalidData("index must be a number".to_string())
71 })?;
72 Ok(ChallengeEvent::SolvedIncorrect(index as usize))
73 }
74 Some("Error") => {
75 let message = value
76 .get("message")
77 .ok_or(EventParseError::MissingData)?
78 .as_str()
79 .ok_or_else(|| {
80 EventParseError::InvalidData("message must be a string".to_string())
81 })?;
82 Ok(ChallengeEvent::Error(message.to_string()))
83 }
84 Some("Started") => Ok(ChallengeEvent::Started),
85 Some("Completed") => Ok(ChallengeEvent::Completed),
86 Some(unknown_action) => Err(EventParseError::UnknownEventType(
87 unknown_action.to_string(),
88 )),
89 None => Err(EventParseError::MissingData),
90 }
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn test_parse_game_event() {
100 let json = r#"{"type":"Game","action":"Started"}"#;
101 let value: serde_json::Value = serde_json::from_str(json).unwrap();
102 let event = Event::try_from(value).unwrap();
103 assert_eq!(event, Event::Game(GameEvent::Started));
104 }
105
106 #[test]
107 fn test_parse_challenge_event() {
108 let json = r#"{"type":"Challenge","action":"SolvedCorrect","index":2}"#;
109 let value: serde_json::Value = serde_json::from_str(json).unwrap();
110 let event = Event::try_from(value).unwrap();
111 assert_eq!(event, Event::Challenge(ChallengeEvent::SolvedCorrect(2)));
112 }
113
114 #[test]
115 fn test_parse_challenge_event_solved_incorrect() {
116 let json = r#"{"type":"Challenge","action":"SolvedIncorrect","index":2}"#;
117 let value: serde_json::Value = serde_json::from_str(json).unwrap();
118 let event = Event::try_from(value).unwrap();
119 assert_eq!(event, Event::Challenge(ChallengeEvent::SolvedIncorrect(2)));
120 }
121
122 #[test]
123 fn test_parse_challenge_event_started() {
124 let json = r#"{"type":"Challenge","action":"Started"}"#;
125 let value: serde_json::Value = serde_json::from_str(json).unwrap();
126 let event = Event::try_from(value).unwrap();
127 assert_eq!(event, Event::Challenge(ChallengeEvent::Started));
128 }
129
130 #[test]
131 fn test_parse_challenge_event_completed() {
132 let json = r#"{"type":"Challenge","action":"Completed"}"#;
133 let value: serde_json::Value = serde_json::from_str(json).unwrap();
134 let event = Event::try_from(value).unwrap();
135 assert_eq!(event, Event::Challenge(ChallengeEvent::Completed));
136 }
137
138 #[test]
139 fn test_parse_challenge_event_error_missing_message() {
140 let json = r#"{"type":"Challenge","action":"Error"}"#;
141 let value: serde_json::Value = serde_json::from_str(json).unwrap();
142 let result = Event::try_from(value);
143 assert_eq!(result, Err(EventParseError::MissingData));
144 }
145
146 #[test]
147 fn test_parse_challenge_event_error_invalid_message() {
148 let json = r#"{"type":"Challenge","action":"Error","message":123}"#;
149 let value: serde_json::Value = serde_json::from_str(json).unwrap();
150 let result = Event::try_from(value);
151 assert_eq!(
152 result,
153 Err(EventParseError::InvalidData(
154 "message must be a string".to_string()
155 ))
156 );
157 }
158
159 #[cfg(target_arch = "wasm32")]
160 mod wasm_tests {
161 use super::*;
162 use wasm_bindgen_test::*;
163
164 wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
165
166 #[wasm_bindgen_test]
167 fn test_parse_game_event_js() {
168 let json = r#"{"type":"Game","action":"Started"}"#;
169 let value: JsValue = js_sys::JSON::parse(json).unwrap();
170 let event = Event::try_from(value).unwrap();
171 assert_eq!(event, Event::Game(GameEvent::Started));
172 }
173
174 #[wasm_bindgen_test]
175 fn test_parse_challenge_event_js() {
176 let json = r#"{"type":"Challenge","action":"SolvedCorrect","index":2}"#;
177 let value: JsValue = js_sys::JSON::parse(json).unwrap();
178 let event = Event::try_from(value).unwrap();
179 assert_eq!(event, Event::Challenge(ChallengeEvent::SolvedCorrect(2)));
180 }
181
182 #[wasm_bindgen_test]
183 fn test_parse_challenge_event_solved_incorrect_js() {
184 let json = r#"{"type":"Challenge","action":"SolvedIncorrect","index":2}"#;
185 let value: JsValue = js_sys::JSON::parse(json).unwrap();
186 let event = Event::try_from(value).unwrap();
187 assert_eq!(event, Event::Challenge(ChallengeEvent::SolvedIncorrect(2)));
188 }
189
190 #[wasm_bindgen_test]
191 fn test_parse_challenge_event_started_js() {
192 let json = r#"{"type":"Challenge","action":"Started"}"#;
193 let value: JsValue = js_sys::JSON::parse(json).unwrap();
194 let event = Event::try_from(value).unwrap();
195 assert_eq!(event, Event::Challenge(ChallengeEvent::Started));
196 }
197
198 #[wasm_bindgen_test]
199 fn test_parse_challenge_event_completed_js() {
200 let json = r#"{"type":"Challenge","action":"Completed"}"#;
201 let value: JsValue = js_sys::JSON::parse(json).unwrap();
202 let event = Event::try_from(value).unwrap();
203 assert_eq!(event, Event::Challenge(ChallengeEvent::Completed));
204 }
205
206 #[wasm_bindgen_test]
207 fn test_parse_game_event_invalid() {
208 let json = r#"{"type":"Game","action":"Invalid"}"#;
209 let value: JsValue = js_sys::JSON::parse(json).unwrap();
210 let event = Event::try_from(value);
211 assert_eq!(
212 event,
213 Err(EventParseError::UnknownEventType("Invalid".to_string()))
214 );
215 }
216
217 #[wasm_bindgen_test]
218 fn test_parse_challenge_event_invalid() {
219 let json = r#"{"type":"Challenge","action":"Invalid"}"#;
220 let value: JsValue = js_sys::JSON::parse(json).unwrap();
221 let event = Event::try_from(value);
222 assert_eq!(
223 event,
224 Err(EventParseError::UnknownEventType("Invalid".to_string()))
225 );
226 }
227
228 #[wasm_bindgen_test]
229 fn test_parse_game_event_missing_data() {
230 let json = r#"{"type":"Game"}"#;
231 let value: JsValue = js_sys::JSON::parse(json).unwrap();
232 let event = Event::try_from(value);
233 assert_eq!(event, Err(EventParseError::MissingData));
234 }
235
236 #[wasm_bindgen_test]
237 fn test_parse_challenge_event_missing_data() {
238 let json = r#"{"type":"Challenge"}"#;
239 let value: JsValue = js_sys::JSON::parse(json).unwrap();
240 let event = Event::try_from(value);
241 assert_eq!(event, Err(EventParseError::MissingData));
242 }
243 }
244}