foch 0.1.0

Paradox mod static analysis toolkit with CLI and EU4-focused language tooling
Documentation
use crate::domain::ParseError;
use crate::domain::game::Game;
use serde::{Deserialize, Serialize};
use std::path::Path;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Playlist {
	#[serde(default)]
	pub game: Game,
	#[serde(default)]
	pub name: String,
	#[serde(default)]
	pub mods: Vec<PlaylistEntry>,
}

impl Default for Playlist {
	fn default() -> Self {
		Self {
			game: Game::Unknown,
			name: String::new(),
			mods: Vec::new(),
		}
	}
}

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct PlaylistEntry {
	#[serde(rename = "displayName", default)]
	pub display_name: Option<String>,
	#[serde(default)]
	pub enabled: bool,
	#[serde(default)]
	pub position: Option<usize>,
	#[serde(rename = "steamId", default)]
	pub steam_id: Option<String>,
}

pub fn load_playlist(path: &Path) -> Result<Playlist, ParseError> {
	let content =
		std::fs::read_to_string(path).map_err(|err| ParseError::io(path.to_path_buf(), err))?;
	serde_json::from_str::<Playlist>(&content)
		.map_err(|err| ParseError::format(path.to_path_buf(), err.to_string()))
}

#[cfg(test)]
mod tests {
	use super::load_playlist;
	use crate::domain::game::Game;
	use std::path::Path;

	#[test]
	fn parses_playlist_from_corpus() {
		let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
		let test_file = manifest_dir
			.join("tests")
			.join("corpus")
			.join("playlist.json");
		let playlist = load_playlist(&test_file).expect("failed to parse test playlist");
		assert_eq!(playlist.game, Game::EuropaUniversalis4);
		assert_eq!(playlist.name, "Initial playset");
		assert_eq!(playlist.mods.len(), 26);
	}
}