summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2019-09-25 11:47:42 +0300
committerLars Wirzenius <liw@liw.fi>2019-09-25 11:47:42 +0300
commitf21e1e0dde83229b024d4960e2e6871bc7727845 (patch)
tree7e2e8ad59ff843e14a895058bc16bc3c472b54fa /src
parent9bd8b8dfa1b898146458bf94c6ec43e27b792b50 (diff)
downloadroadmap-f21e1e0dde83229b024d4960e2e6871bc7727845.tar.gz
Change: check for non-existent dependencies
Also, rework how errors are defined
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs39
1 files changed, 36 insertions, 3 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 97ce6c3..2a46767 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -33,6 +33,8 @@ use serde_yaml;
use serde_yaml::Value;
use std::collections::HashMap;
use textwrap::fill;
+use std::fmt;
+use std::error::Error;
/// A step in a roadmap.
#[derive(Clone,Debug,PartialEq)]
@@ -95,6 +97,17 @@ pub struct Roadmap {
steps: Vec<Step>,
}
+#[derive(Debug)]
+struct ParseError(String);
+
+impl fmt::Display for ParseError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "ERROR: {}", self.0)
+ }
+}
+
+impl Error for ParseError {}
+
impl Roadmap {
/// Create a new, empty roadmap.
pub fn new() -> Roadmap {
@@ -102,7 +115,7 @@ impl Roadmap {
}
/// Create a new roadmap from a YAML representation.
- pub fn from_yaml(yaml: &str) -> Result<Roadmap, Box<dyn std::error::Error>> {
+ pub fn from_yaml(yaml: &str) -> Result<Roadmap, Box<dyn Error>> {
let mut roadmap = Roadmap::new();
let map: HashMap<String, serde_yaml::Value> = serde_yaml::from_str(yaml)?;
@@ -111,6 +124,7 @@ impl Roadmap {
roadmap.add_step(&step)?;
}
+ roadmap.validate()?;
Ok(roadmap)
}
@@ -170,6 +184,25 @@ impl Roadmap {
}
}
+ // Validate that the parsed, constructed roadmap is valid.
+ fn validate(&self) -> Result<(), Box<dyn std::error::Error>> {
+ // Does every dependency exist?
+ for step in self.steps.iter() {
+ for depname in step.dependencies() {
+ match self.get_step(depname) {
+ None => {
+ let msg = format!("step {} depends on missing {}",
+ step.name(), depname);
+ return Result::Err(Box::new(ParseError(msg.into())));
+ }
+ Some(_) => (),
+ }
+ }
+ }
+
+ Ok(())
+ }
+
/// Return list of step names.
pub fn step_names<'a>(&'a self) -> Vec<&'a str> {
let mut names = vec![];
@@ -397,8 +430,8 @@ mod tests {
}
#[test]
- fn parse_yaml_map_entries_not_maps() {
- let r = Roadmap::from_yaml("foo: []");
+ fn parse_yaml_unknown_dep() {
+ let r = Roadmap::from_yaml("foo: {depends: [bar]}");
match r {
Ok(_) => panic!("expected a parse error"),
_ => (),