1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
use std::fmt; use hyper::Error as HyperError; use hyper::error::ParseError; use std::error::Error as StdError; use std::io; use std::collections::HashMap; use serde_json; use serde_json::Error as JsonError; use self::Error::{Json, Http, Io, Query, Url}; #[derive(Debug)] pub enum Error { Json(serde_json::Error), Http(HyperError), Url(ParseError), Io(io::Error), Query { error: String, description: String }, } impl Error { pub fn from_couch(msg: &str) -> Error { let convert = match serde_json::from_str::<HashMap<String, String>>(msg) { Ok(map) => map, Err(e) => return Json(e), }; let err = match convert.get("error") { Some(msg) => msg.to_string(), None => "Unknown".to_string(), }; let description = match convert.get("reason") { Some(msg) => msg.to_string(), None => "unknown reason".to_string(), }; Query { error: err, description: description, } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Json(ref e) => write!(f, "{}", e), Http(ref e) => write!(f, "{}", e), Io(ref e) => write!(f, "{}", e), Url(ref e) => write!(f, "{}", e), Query { ref error, ref description } => write!(f, "{}:{}", error, description), } } } impl StdError for Error { fn description(&self) -> &str { match *self { Json(ref e) => e.description(), Http(ref e) => e.description(), Io(ref e) => e.description(), Url(ref e) => e.description(), Query { .. } => "CouchDB responded with an error", } } fn cause(&self) -> Option<&StdError> { match *self { Json(ref e) => Some(e), Http(ref e) => Some(e), Io(ref e) => Some(e), Url(ref e) => Some(e), Query { .. } => None, } } } impl From<HyperError> for Error { fn from(err: HyperError) -> Error { Http(err) } } impl From<ParseError> for Error { fn from(err: ParseError) -> Error { Url(err) } } impl From<JsonError> for Error { fn from(err: JsonError) -> Error { Json(err) } } impl From<io::Error> for Error { fn from(err: io::Error) -> Error { Io(err) } } #[cfg(test)] mod tests { use super::*; #[test] fn from_couch_warns_on_json_parse_error() { match Error::from_couch("This will not parse") { Json(_) => assert!(true), _ => panic!("I was expecting a Json error!"), } } #[test] fn from_couch_returns_parsed_json_error() { let str = "{\"error\":\"not_found\",\"reason\":\"Database does not exist.\"}"; match Error::from_couch(str) { Query { ref error, .. } => assert_eq!(error, "not_found"), _ => panic!("I was expecting query error"), } } #[test] fn from_couch_works_with_different_hashmap_values() { let str = "{\"oops\":\"not_found\",\"what_happened\":\"Database does not exist.\"}"; match Error::from_couch(str) { Query { ref error, ref description } => { assert_eq!(error, "Unknown"); assert_eq!(description, "unknown reason"); } _ => panic!("I was expecting query error"), } } }