use std::collections::HashMap;
use std::path::Path;
use serde::{Deserialize, Serialize};
use anyhow::{bail, Result};
use crate::util::is_valid_version;
#[derive(Deserialize, Serialize, Debug)]
pub struct FrateToml {
pub project: Project,
pub dependencies: HashMap<String, String>
}
#[derive(Deserialize, Serialize, Debug)]
pub struct Project {
pub name: String,
pub version: String,
}
impl FrateToml {
pub fn default(name: &str) -> FrateToml {
FrateToml {
project: Project {
name: String::from(name),
version: String::from("0.1.0"),
},
dependencies: HashMap::new()
}
}
pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
let toml_str = toml::to_string_pretty(self)?;
std::fs::write(path, toml_str)?;
Ok(())
}
pub fn load<P: AsRef<Path>>(path: P) -> Result<FrateToml> {
let toml = std::fs::read_to_string(path)?;
toml::from_str(&toml).map_err(|e| e.into())
}
pub fn add(&mut self, name: &str, version: &str) -> Result<()> {
if !is_valid_version(version) {
bail!("Invalid version: {}", version);
}
if self.dependencies.contains_key(name) {
bail!("Dependency {} already exists", name);
}
self.dependencies.insert(name.to_string(), version.to_string());
Ok(())
}
pub fn remove(&mut self, name: &str) {
self.dependencies.remove(name);
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
fn sample_with_dep() -> FrateToml {
let mut frate = FrateToml::default("test");
frate.add("tool", "1.2.3").unwrap();
frate
}
#[test]
fn test_default() {
let frate = FrateToml::default("myproj");
assert_eq!(frate.project.name, "myproj");
assert_eq!(frate.project.version, "0.1.0");
assert!(frate.dependencies.is_empty());
}
#[test]
fn test_save_and_load() {
let dir = tempdir().unwrap();
let file_path = dir.path().join("frate.toml");
let frate = sample_with_dep();
frate.save(&file_path).unwrap();
let loaded = FrateToml::load(&file_path).unwrap();
assert_eq!(loaded.project.name, "test");
assert_eq!(loaded.project.version, "0.1.0");
assert_eq!(loaded.dependencies.get("tool").unwrap(), "1.2.3");
}
#[test]
fn test_add_valid() {
let mut frate = FrateToml::default("x");
frate.add("foo", "1.0.0").unwrap();
assert_eq!(frate.dependencies.get("foo").unwrap(), "1.0.0");
}
#[test]
fn test_add_invalid_version() {
let mut frate = FrateToml::default("x");
let result = frate.add("foo", "bad.version");
assert!(result.is_err());
}
#[test]
fn test_add_duplicate() {
let mut frate = FrateToml::default("x");
frate.add("foo", "1.0.0").unwrap();
let result = frate.add("foo", "1.0.0");
assert!(result.is_err());
}
#[test]
fn test_remove_existing() {
let mut frate = sample_with_dep();
frate.remove("tool");
assert!(!frate.dependencies.contains_key("tool"));
}
#[test]
fn test_remove_non_existing() {
let mut frate = FrateToml::default("x");
frate.remove("nonexistent");
assert!(frate.dependencies.is_empty());
}
}