mirror of
https://github.com/haraldh/chainerror.git
synced 2025-01-31 00:56:41 +01:00
factor out example
This commit is contained in:
parent
59066788b4
commit
d1295092a4
|
@ -5,7 +5,7 @@ authors = ["Harald Hoyer <harald@redhat.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "debug-cause", "fileline" ]
|
default = [ "debug-cause", "fileline"]
|
||||||
fileline = []
|
fileline = []
|
||||||
display-cause = []
|
display-cause = []
|
||||||
debug-cause = []
|
debug-cause = []
|
169
examples/configapp.rs
Normal file
169
examples/configapp.rs
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use std::io::Error as IoError;
|
||||||
|
use std::io::ErrorKind as IoErrorKind;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use chainerror::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
enum ParseError {
|
||||||
|
InvalidValue(u32),
|
||||||
|
InvalidParameter(String),
|
||||||
|
NoOpen,
|
||||||
|
NoClose,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Display for ParseError {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ParseError::InvalidValue(a) => write!(f, "InvalidValue: {}", a),
|
||||||
|
ParseError::InvalidParameter(a) => write!(f, "InvalidParameter: '{}'", a),
|
||||||
|
ParseError::NoOpen => write!(f, "No opening '{{' in config file"),
|
||||||
|
ParseError::NoClose => write!(f, "No closing '}}' in config file"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_config(c: String) -> Result<(), Box<Error>> {
|
||||||
|
if !c.starts_with('{') {
|
||||||
|
Err(cherr!(ParseError::NoOpen))?;
|
||||||
|
}
|
||||||
|
if !c.ends_with('}') {
|
||||||
|
Err(cherr!(ParseError::NoClose))?;
|
||||||
|
}
|
||||||
|
let c = &c[1..(c.len() - 1)];
|
||||||
|
let v = c
|
||||||
|
.parse::<u32>()
|
||||||
|
.map_err(|e| cherr!(e, ParseError::InvalidParameter(c.into())))?;
|
||||||
|
if v > 100 {
|
||||||
|
Err(cherr!(ParseError::InvalidValue(v)))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
derive_str_cherr!(ConfigFileError);
|
||||||
|
derive_str_cherr!(SeriousError);
|
||||||
|
derive_str_cherr!(FileError);
|
||||||
|
derive_str_cherr!(AppError);
|
||||||
|
|
||||||
|
fn file_reader(_filename: &Path) -> Result<(), Box<Error>> {
|
||||||
|
Err(IoError::from(IoErrorKind::NotFound)).map_err(mstrerr!(FileError, "File reader error"))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_config(filename: &Path) -> Result<(), Box<Error>> {
|
||||||
|
if filename.eq(Path::new("global.ini")) {
|
||||||
|
// assume we got an IO error
|
||||||
|
file_reader(filename).map_err(mstrerr!(
|
||||||
|
ConfigFileError,
|
||||||
|
"Error reading file {:?}",
|
||||||
|
filename
|
||||||
|
))?;
|
||||||
|
}
|
||||||
|
// assume we read some buffer
|
||||||
|
if filename.eq(Path::new("local.ini")) {
|
||||||
|
let buf = String::from("{1000}");
|
||||||
|
parse_config(buf)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if filename.eq(Path::new("user.ini")) {
|
||||||
|
let buf = String::from("foo");
|
||||||
|
parse_config(buf)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if filename.eq(Path::new("user2.ini")) {
|
||||||
|
let buf = String::from("{foo");
|
||||||
|
parse_config(buf)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if filename.eq(Path::new("user3.ini")) {
|
||||||
|
let buf = String::from("{foo}");
|
||||||
|
parse_config(buf)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if filename.eq(Path::new("custom.ini")) {
|
||||||
|
let buf = String::from("{10}");
|
||||||
|
parse_config(buf)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if filename.eq(Path::new("essential.ini")) {
|
||||||
|
Err(cherr!(SeriousError("Something is really wrong".into())))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_verbose_config(p: &str) -> Result<(), Box<Error>> {
|
||||||
|
eprintln!("Reading '{}' ... ", p);
|
||||||
|
read_config(Path::new(p)).map_err(mstrerr!(AppError, "{}", p))?;
|
||||||
|
eprintln!("Ok reading {}", p);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_app(debug: bool) -> Result<(), Box<Error>> {
|
||||||
|
for p in &[
|
||||||
|
"global.ini",
|
||||||
|
"local.ini",
|
||||||
|
"user.ini",
|
||||||
|
"user2.ini",
|
||||||
|
"user3.ini",
|
||||||
|
"custom.ini",
|
||||||
|
"essential.ini",
|
||||||
|
] {
|
||||||
|
if let Err(e) = read_verbose_config(p) {
|
||||||
|
assert!(e.is_chain::<AppError>());
|
||||||
|
let app_err = e.downcast_chain_ref::<AppError>().unwrap();
|
||||||
|
|
||||||
|
if app_err.find_kind::<SeriousError>().is_some() {
|
||||||
|
// Bail out on SeriousError
|
||||||
|
eprintln!("---> Serious Error:\n{:?}", e);
|
||||||
|
Err(cherr!(e, AppError("Seriously".into())))?;
|
||||||
|
} else if let Some(cfg_error) = app_err.find_kind::<ConfigFileError>() {
|
||||||
|
if debug {
|
||||||
|
eprintln!("{:?}\n", cfg_error);
|
||||||
|
} else {
|
||||||
|
// Deep Error handling
|
||||||
|
if let Some(chioerror) = cfg_error.find_kind::<IoError>() {
|
||||||
|
let ioerror = chioerror.kind();
|
||||||
|
match ioerror.kind() {
|
||||||
|
IoErrorKind::NotFound => {
|
||||||
|
eprint!("Ignoring missing file");
|
||||||
|
if let Some(root_cause) = cfg_error.root_cause() {
|
||||||
|
eprint!(", because of: {}\n", root_cause);
|
||||||
|
}
|
||||||
|
eprintln!();
|
||||||
|
}
|
||||||
|
_ => Err(cherr!(e, AppError("Unhandled IOError".into())))?,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!("ConfigFileError for: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if debug {
|
||||||
|
eprintln!("Error reading:\n{:?}\n", e)
|
||||||
|
} else {
|
||||||
|
eprintln!("Error reading: {}\n", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eprintln!();
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<Error>> {
|
||||||
|
eprintln!("Display:\n");
|
||||||
|
let e = start_app(false).unwrap_err();
|
||||||
|
assert!(e.is_chain::<AppError>());
|
||||||
|
eprintln!("\n\n==================================");
|
||||||
|
eprintln!("==== Debug output");
|
||||||
|
eprintln!("==================================\n");
|
||||||
|
let r = start_app(true);
|
||||||
|
|
||||||
|
eprintln!("\n\n==================================");
|
||||||
|
eprintln!("==== Main return output");
|
||||||
|
eprintln!("==================================\n");
|
||||||
|
r
|
||||||
|
}
|
72
src/lib.rs
72
src/lib.rs
|
@ -302,12 +302,9 @@ mod tests {
|
||||||
derive_str_cherr!(FileError);
|
derive_str_cherr!(FileError);
|
||||||
derive_str_cherr!(AppError);
|
derive_str_cherr!(AppError);
|
||||||
|
|
||||||
fn file_reader(filename: &Path) -> Result<(), Box<Error>> {
|
fn file_reader(_filename: &Path) -> Result<(), Box<Error>> {
|
||||||
Err(IoError::from(IoErrorKind::NotFound)).map_err(mstrerr!(
|
Err(IoError::from(IoErrorKind::NotFound))
|
||||||
FileError,
|
.map_err(mstrerr!(FileError, "File reader error"))?;
|
||||||
"Can't find {:?}",
|
|
||||||
filename
|
|
||||||
))?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +313,7 @@ mod tests {
|
||||||
// assume we got an IO error
|
// assume we got an IO error
|
||||||
file_reader(filename).map_err(mstrerr!(
|
file_reader(filename).map_err(mstrerr!(
|
||||||
ConfigFileError,
|
ConfigFileError,
|
||||||
"Can't find {:?}",
|
"Error reading file {:?}",
|
||||||
filename
|
filename
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
|
@ -353,14 +350,13 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_verbose_config(p: &str) -> Result<(), Box<Error>> {
|
fn read_config_pre(p: &str) -> Result<(), Box<Error>> {
|
||||||
eprintln!("Reading '{}' ... ", p);
|
|
||||||
read_config(Path::new(p)).map_err(mstrerr!(AppError, "{}", p))?;
|
read_config(Path::new(p)).map_err(mstrerr!(AppError, "{}", p))?;
|
||||||
eprintln!("Ok reading {}", p);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_app(debug: bool) -> Result<(), Box<Error>> {
|
#[test]
|
||||||
|
fn test_chain_error() {
|
||||||
for p in &[
|
for p in &[
|
||||||
"global.ini",
|
"global.ini",
|
||||||
"local.ini",
|
"local.ini",
|
||||||
|
@ -370,57 +366,17 @@ mod tests {
|
||||||
"custom.ini",
|
"custom.ini",
|
||||||
"essential.ini",
|
"essential.ini",
|
||||||
] {
|
] {
|
||||||
if let Err(e) = read_verbose_config(p) {
|
if let Err(e) = read_config_pre(p) {
|
||||||
assert!(e.is_chain::<AppError>());
|
|
||||||
let app_err = e.downcast_chain_ref::<AppError>().unwrap();
|
let app_err = e.downcast_chain_ref::<AppError>().unwrap();
|
||||||
|
|
||||||
if app_err.find_kind::<SeriousError>().is_some() {
|
match p {
|
||||||
// Bail out on SeriousError
|
&"global.ini" => {
|
||||||
eprintln!("---> Serious Error:\n{:?}", e);
|
assert!(app_err.find_kind::<ConfigFileError>().is_some());
|
||||||
Err(cherr!(e, AppError("Seriously".into())))?;
|
assert!(app_err.root_cause().unwrap().is::<IoError>());
|
||||||
} else if let Some(cfg_error) = app_err.find_kind::<ConfigFileError>() {
|
},
|
||||||
if debug {
|
_ => {}
|
||||||
eprintln!("{:?}\n", cfg_error);
|
|
||||||
} else {
|
|
||||||
// Deep Error handling
|
|
||||||
if let Some(chioerror) = cfg_error.find_kind::<IoError>() {
|
|
||||||
let ioerror = chioerror.kind();
|
|
||||||
match ioerror.kind() {
|
|
||||||
IoErrorKind::NotFound => {
|
|
||||||
eprint!("Ignoring missing file");
|
|
||||||
if let Some(root_cause) = cfg_error.root_cause() {
|
|
||||||
eprint!(", because of: {}\n", root_cause);
|
|
||||||
}
|
|
||||||
eprintln!();
|
|
||||||
}
|
|
||||||
_ => Err(cherr!(e, AppError("Unhandled IOError".into())))?,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
eprintln!("ConfigFileError for: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if debug {
|
|
||||||
eprintln!("Error reading:\n{:?}\n", e)
|
|
||||||
} else {
|
|
||||||
eprintln!("Error reading: {}\n", e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
eprintln!();
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_chain_error() {
|
|
||||||
eprintln!("Display:\n");
|
|
||||||
let e = start_app(false).unwrap_err();
|
|
||||||
assert!(e.is_chain::<AppError>());
|
|
||||||
eprintln!("\n\n==================================");
|
|
||||||
eprintln!("==== Debug output");
|
|
||||||
eprintln!("==================================\n");
|
|
||||||
let r = start_app(true);
|
|
||||||
assert!(r.unwrap_err().is_chain::<AppError>());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue