use crate::ErrorList;
use crate::FullContext;
use crate::Output;
use crate::Position;
use crate::Warning;
use crate::WarningKind;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct StoryData {
pub ifid: String,
pub format: Option<String>,
#[serde(rename = "format-version")]
pub format_version: Option<String>,
pub start: Option<String>,
#[serde(rename = "tag-colors")]
pub tag_colors: Option<HashMap<String, String>>,
pub zoom: Option<f32>,
}
impl StoryData {
pub fn parse(context: FullContext) -> Output<Result<Option<Self>, ErrorList>> {
let mut warnings = Vec::new();
let res: serde_json::Result<StoryData> = serde_json::from_str(context.get_contents());
let story_data = if res.is_ok() {
Some(res.ok().unwrap())
} else {
let err = res.err().unwrap();
let err_string = format!("{}", err).split(" at ").next().unwrap().to_string();
warnings.push(Warning::new(
WarningKind::JsonError(err_string),
Some(context.subcontext(
Position::rel(err.line(), err.column())
..=Position::rel(err.line(), err.column()),
)),
));
None
};
Output::new(Ok(story_data)).with_warnings(warnings)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_example() {
let input = r#"{
"ifid": "D674C58C-DEFA-4F70-B7A2-27742230C0FC",
"format": "SugarCube",
"format-version": "2.28.2",
"start": "My Starting Passage",
"tag-colors": {
"bar": "green",
"foo": "red",
"qaz": "blue"
},
"zoom": 0.25
}
"#
.to_string();
let out = StoryData::parse(FullContext::from(None, input));
assert!(!out.has_warnings());
let (res, _) = out.take();
assert!(res.is_ok());
let data = res.ok().unwrap();
let expected = if let Some(story_data) = data {
assert_eq!(story_data.ifid, "D674C58C-DEFA-4F70-B7A2-27742230C0FC");
assert_eq!(story_data.format, Some("SugarCube".to_string()));
assert_eq!(story_data.format_version, Some("2.28.2".to_string()));
assert_eq!(story_data.start, Some("My Starting Passage".to_string()));
assert_eq!(story_data.zoom, Some(0.25));
let expected = if let Some(tag_colors) = story_data.tag_colors {
assert_eq!(tag_colors["bar"], "green");
assert_eq!(tag_colors["foo"], "red");
assert_eq!(tag_colors["qaz"], "blue");
true
} else {
false
};
assert!(expected);
true
} else {
false
};
assert!(expected);
}
#[test]
fn test_malformed() {
let input = r#"{
"ifid": "D674C58C-DEFA-4F70-B7A2-27742230C0FC",
"format": "SugarCube",
"format-version": "2.28.2",
"start": "My Starting Passage",
"tag-colors": {
"#
.to_string();
let out = StoryData::parse(FullContext::from(None, input));
assert!(out.has_warnings());
let (res, warnings) = out.take();
assert!(res.is_ok());
let data = res.ok().unwrap();
assert!(data.is_none());
assert_eq!(warnings.len(), 1);
assert!(
if let WarningKind::JsonError(_) = &warnings[0].kind {
true
} else {
false
}
);
}
}