mirror of
				https://github.com/haraldh/chainerror.git
				synced 2025-10-30 22:39:34 +01:00 
			
		
		
		
	add tutorial
This commit is contained in:
		
							parent
							
								
									d1295092a4
								
							
						
					
					
						commit
						46e2c78aa8
					
				
					 13 changed files with 594 additions and 298 deletions
				
			
		|  | @ -1,169 +0,0 @@ | ||||||
| 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 |  | ||||||
| } |  | ||||||
							
								
								
									
										34
									
								
								examples/tutorial1.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								examples/tutorial1.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial1 | ||||||
|  | Error: StringError("func1 error") | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use std::error::Error; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err("do_some_io error")?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(_) = do_some_io() { | ||||||
|  |         Err("func2 error")?; | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func1() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(_) = func2() { | ||||||
|  |         Err("func1 error")?; | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     func1() | ||||||
|  | } | ||||||
							
								
								
									
										74
									
								
								examples/tutorial10.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								examples/tutorial10.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,74 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial10 | ||||||
|  | Main Error Report: func1 error calling func2 | ||||||
|  | Error reported by Func2Error: Error reading 'foo.txt' | ||||||
|  | 
 | ||||||
|  | Debug Error: | ||||||
|  | examples/tutorial10.rs:49: Func2 | ||||||
|  | Caused by: | ||||||
|  | examples/tutorial10.rs:29: Func2Error(Error reading 'foo.txt') | ||||||
|  | Caused by: | ||||||
|  | Kind(NotFound) | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use chainerror::prelude::*; | ||||||
|  | use std::error::Error; | ||||||
|  | use std::io; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err(io::Error::from(io::ErrorKind::NotFound))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | derive_str_cherr!(Func2Error); | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     let filename = "foo.txt"; | ||||||
|  |     do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | enum Func1Error { | ||||||
|  |     Func2, | ||||||
|  |     IO(String), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ::std::fmt::Display for Func1Error { | ||||||
|  |     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||||
|  |         match self { | ||||||
|  |             Func1Error::Func2 => write!(f, "func1 error calling func2"), | ||||||
|  |             Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func1() -> ChainResult<(), Func1Error> { | ||||||
|  |     func2().map_err(|e| cherr!(e, Func1Error::Func2))?; | ||||||
|  |     let filename = String::from("bar.txt"); | ||||||
|  |     do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func1() { | ||||||
|  |         match e.kind() { | ||||||
|  |             Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"), | ||||||
|  |             Func1Error::IO(filename) => { | ||||||
|  |                 eprintln!("Main Error Report: func1 error reading '{}'", filename) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if let Some(e) = e.find_chain_cause::<Func2Error>() { | ||||||
|  |             eprintln!("Error reported by Func2Error: {}", e) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         eprintln!("\nDebug Error:\n{:?}", e); | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										79
									
								
								examples/tutorial11.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								examples/tutorial11.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,79 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial11 | ||||||
|  | Main Error Report: func1 error calling func2 | ||||||
|  | Error reported by Func2Error: Error reading 'foo.txt' | ||||||
|  | 
 | ||||||
|  | Debug Error: | ||||||
|  | examples/tutorial11.rs:57: func1 error calling func2 | ||||||
|  | Caused by: | ||||||
|  | examples/tutorial11.rs:32: Func2Error(Error reading 'foo.txt') | ||||||
|  | Caused by: | ||||||
|  | Kind(NotFound) | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use chainerror::prelude::*; | ||||||
|  | use std::error::Error; | ||||||
|  | use std::io; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err(io::Error::from(io::ErrorKind::NotFound))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | derive_str_cherr!(Func2Error); | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     let filename = "foo.txt"; | ||||||
|  |     do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | enum Func1Error { | ||||||
|  |     Func2, | ||||||
|  |     IO(String), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ::std::fmt::Display for Func1Error { | ||||||
|  |     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||||
|  |         match self { | ||||||
|  |             Func1Error::Func2 => write!(f, "func1 error calling func2"), | ||||||
|  |             Func1Error::IO(filename) => write!(f, "Error reading '{}'", filename), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ::std::fmt::Debug for Func1Error { | ||||||
|  |     fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||||||
|  |         write!(f, "{}", self) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func1() -> ChainResult<(), Func1Error> { | ||||||
|  |     func2().map_err(|e| cherr!(e, Func1Error::Func2))?; | ||||||
|  |     let filename = String::from("bar.txt"); | ||||||
|  |     do_some_io().map_err(|e| cherr!(e, Func1Error::IO(filename)))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func1() { | ||||||
|  |         match e.kind() { | ||||||
|  |             Func1Error::Func2 => eprintln!("Main Error Report: func1 error calling func2"), | ||||||
|  |             Func1Error::IO(filename) => { | ||||||
|  |                 eprintln!("Main Error Report: func1 error reading '{}'", filename) | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if let Some(e) = e.find_chain_cause::<Func2Error>() { | ||||||
|  |             eprintln!("Error reported by Func2Error: {}", e) | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         eprintln!("\nDebug Error:\n{:?}", e); | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								examples/tutorial2.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								examples/tutorial2.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial2 | ||||||
|  | Error: examples/tutorial2.rs:28: "func1 error" | ||||||
|  | Caused by: | ||||||
|  | examples/tutorial2.rs:21: "func2 error" | ||||||
|  | Caused by: | ||||||
|  | StringError("do_some_io error") | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use chainerror::prelude::*; | ||||||
|  | use std::error::Error; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err("do_some_io error")?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = do_some_io() { | ||||||
|  |         Err(cherr!(e, "func2 error"))?; | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func1() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func2() { | ||||||
|  |         Err(cherr!(e, "func1 error"))?; | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     func1() | ||||||
|  | } | ||||||
							
								
								
									
										38
									
								
								examples/tutorial3.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								examples/tutorial3.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial3 | ||||||
|  | examples/tutorial3.rs:30: "func1 error" | ||||||
|  | Caused by: | ||||||
|  | examples/tutorial3.rs:25: "func2 error" | ||||||
|  | Caused by: | ||||||
|  | StringError("do_some_io error") | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use chainerror::prelude::*; | ||||||
|  | use std::error::Error; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err("do_some_io error")?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     do_some_io().map_err(|e| cherr!(e, "func2 error"))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func1() -> Result<(), Box<Error>> { | ||||||
|  |     func2().map_err(|e| cherr!(e, "func1 error"))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func1() { | ||||||
|  |         eprintln!("{:?}", e); | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										38
									
								
								examples/tutorial4.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								examples/tutorial4.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial4 | ||||||
|  | examples/tutorial4.rs:29: "func1 error" | ||||||
|  | Caused by: | ||||||
|  | examples/tutorial4.rs:24: "func2 error" | ||||||
|  | Caused by: | ||||||
|  | StringError("do_some_io error") | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use chainerror::prelude::*; | ||||||
|  | use std::error::Error; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err("do_some_io error")?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     do_some_io().map_err(mstrerr!("func2 error"))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func1() -> Result<(), Box<Error>> { | ||||||
|  |     func2().map_err(mstrerr!("func1 error"))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func1() { | ||||||
|  |         eprintln!("{:?}", e); | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								examples/tutorial5.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								examples/tutorial5.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial5 | ||||||
|  | Func2 failed because of 'entity not found' | ||||||
|  | func1 error | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use chainerror::prelude::*; | ||||||
|  | use std::error::Error; | ||||||
|  | use std::io; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err(io::Error::from(io::ErrorKind::NotFound))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     let filename = "foo.txt"; | ||||||
|  |     do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func1() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func2() { | ||||||
|  |         if let Some(s) = e.source() { | ||||||
|  |             eprintln!("func2 failed because of '{}'", s); | ||||||
|  |             Err(e).map_err(mstrerr!("func1 error"))?; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func1() { | ||||||
|  |         eprintln!("{}", e); | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										52
									
								
								examples/tutorial6.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								examples/tutorial6.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,52 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial6 | ||||||
|  | Error: func1 error | ||||||
|  | caused by: Error reading 'foo.txt' | ||||||
|  | caused by: std::io::Error: entity not found | ||||||
|  | of kind: std::io::ErrorKind::NotFound | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use chainerror::prelude::*; | ||||||
|  | use std::error::Error; | ||||||
|  | use std::io; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err(io::Error::from(io::ErrorKind::NotFound))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     let filename = "foo.txt"; | ||||||
|  |     do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func1() -> Result<(), Box<Error>> { | ||||||
|  |     func2().map_err(mstrerr!("func1 error"))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func1() { | ||||||
|  |         eprintln!("Error: {}", e); | ||||||
|  |         let mut s = e.as_ref(); | ||||||
|  |         while let Some(c) = s.source() { | ||||||
|  |             if let Some(ioerror) = c.downcast_ref::<io::Error>() { | ||||||
|  |                 eprintln!("caused by: std::io::Error: {}", ioerror); | ||||||
|  |                 match ioerror.kind() { | ||||||
|  |                     io::ErrorKind::NotFound => eprintln!("of kind: std::io::ErrorKind::NotFound"), | ||||||
|  |                     _ => {} | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 eprintln!("caused by: {}", c); | ||||||
|  |             } | ||||||
|  |             s = c; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								examples/tutorial7.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								examples/tutorial7.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial7 | ||||||
|  | Error: func1 error | ||||||
|  | caused by: std::io::Error: entity not found | ||||||
|  | of kind: std::io::ErrorKind::NotFound | ||||||
|  | The root cause was: std::io::Error: Kind( | ||||||
|  |     NotFound | ||||||
|  | ) | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use chainerror::prelude::*; | ||||||
|  | use std::error::Error; | ||||||
|  | use std::io; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err(io::Error::from(io::ErrorKind::NotFound))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     let filename = "foo.txt"; | ||||||
|  |     do_some_io().map_err(mstrerr!("Error reading '{}'", filename))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn func1() -> Result<(), Box<Error>> { | ||||||
|  |     func2().map_err(mstrerr!("func1 error"))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func1() { | ||||||
|  |         eprintln!("Error: {}", e); | ||||||
|  |         if let Some(s) = e.downcast_chain_ref::<String>() { | ||||||
|  |             if let Some(ioerror) = s.find_cause::<io::Error>() { | ||||||
|  |                 eprintln!("caused by: std::io::Error: {}", ioerror); | ||||||
|  |                 match ioerror.kind() { | ||||||
|  |                     io::ErrorKind::NotFound => eprintln!("of kind: std::io::ErrorKind::NotFound"), | ||||||
|  |                     _ => {} | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if let Some(e) = s.root_cause() { | ||||||
|  |                 let ioerror = e.downcast_ref::<io::Error>().unwrap(); | ||||||
|  |                 eprintln!("The root cause was: std::io::Error: {:#?}", ioerror); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								examples/tutorial8.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								examples/tutorial8.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial8 | ||||||
|  | Func1Error: func1 error | ||||||
|  | Func2Error: Error reading 'foo.txt' | ||||||
|  | Debug Func2Error: | ||||||
|  | examples/tutorial8.rs:27: Func2Error(Error reading 'foo.txt') | ||||||
|  | Caused by: | ||||||
|  | Kind(NotFound) | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use chainerror::prelude::*; | ||||||
|  | use std::error::Error; | ||||||
|  | use std::io; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err(io::Error::from(io::ErrorKind::NotFound))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | derive_str_cherr!(Func2Error); | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     let filename = "foo.txt"; | ||||||
|  |     do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | derive_str_cherr!(Func1Error); | ||||||
|  | 
 | ||||||
|  | fn func1() -> Result<(), Box<Error>> { | ||||||
|  |     func2().map_err(mstrerr!(Func1Error, "func1 error"))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func1() { | ||||||
|  |         if let Some(f1err) = e.downcast_chain_ref::<Func1Error>() { | ||||||
|  |             eprintln!("Func1Error: {}", f1err); | ||||||
|  | 
 | ||||||
|  |             if let Some(f2err) = f1err.find_cause::<ChainError<Func2Error>>() { | ||||||
|  |                 eprintln!("Func2Error: {}", f2err); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if let Some(f2err) = f1err.find_chain_cause::<Func2Error>() { | ||||||
|  |                 eprintln!("Debug Func2Error:\n{:?}", f2err); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										54
									
								
								examples/tutorial9.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								examples/tutorial9.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,54 @@ | ||||||
|  | /*! | ||||||
|  | 
 | ||||||
|  | ~~~bash | ||||||
|  | $ cargo run -q --example tutorial9 | ||||||
|  | Func1ErrorFunc2: | ||||||
|  | examples/tutorial9.rs:37: Func1ErrorFunc2(func1 error calling func2) | ||||||
|  | Caused by: | ||||||
|  | examples/tutorial9.rs:29: Func2Error(Error reading 'foo.txt') | ||||||
|  | Caused by: | ||||||
|  | Kind(NotFound) | ||||||
|  | ~~~ | ||||||
|  | 
 | ||||||
|  | !*/ | ||||||
|  | 
 | ||||||
|  | use chainerror::prelude::*; | ||||||
|  | use std::error::Error; | ||||||
|  | use std::io; | ||||||
|  | use std::result::Result; | ||||||
|  | 
 | ||||||
|  | fn do_some_io() -> Result<(), Box<Error>> { | ||||||
|  |     Err(io::Error::from(io::ErrorKind::NotFound))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | derive_str_cherr!(Func2Error); | ||||||
|  | 
 | ||||||
|  | fn func2() -> Result<(), Box<Error>> { | ||||||
|  |     let filename = "foo.txt"; | ||||||
|  |     do_some_io().map_err(mstrerr!(Func2Error, "Error reading '{}'", filename))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | derive_str_cherr!(Func1ErrorFunc2); | ||||||
|  | derive_str_cherr!(Func1ErrorIO); | ||||||
|  | 
 | ||||||
|  | fn func1() -> Result<(), Box<Error>> { | ||||||
|  |     func2().map_err(mstrerr!(Func1ErrorFunc2, "func1 error calling func2"))?; | ||||||
|  |     let filename = "bar.txt"; | ||||||
|  |     do_some_io().map_err(mstrerr!(Func1ErrorIO, "Error reading '{}'", filename))?; | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn main() -> Result<(), Box<Error>> { | ||||||
|  |     if let Err(e) = func1() { | ||||||
|  |         if let Some(s) = e.downcast_ref::<ChainError<Func1ErrorIO>>() { | ||||||
|  |             eprintln!("Func1ErrorIO:\n{:?}", s); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if let Some(s) = try_cherr_ref!(e, Func1ErrorFunc2) { | ||||||
|  |             eprintln!("Func1ErrorFunc2:\n{:?}", s); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
							
								
								
									
										163
									
								
								src/lib.rs
									
										
									
									
									
								
							
							
						
						
									
										163
									
								
								src/lib.rs
									
										
									
									
									
								
							|  | @ -1,5 +1,6 @@ | ||||||
| use std::error::Error; | use std::error::Error; | ||||||
| use std::fmt::{Debug, Display, Formatter, Result}; | use std::fmt::{Debug, Display, Formatter, Result}; | ||||||
|  | use std::result::Result as StdResult; | ||||||
| 
 | 
 | ||||||
| pub struct ChainError<T> { | pub struct ChainError<T> { | ||||||
|     #[cfg(feature = "fileline")] |     #[cfg(feature = "fileline")] | ||||||
|  | @ -8,6 +9,8 @@ pub struct ChainError<T> { | ||||||
|     error_cause: Option<Box<dyn Error + 'static>>, |     error_cause: Option<Box<dyn Error + 'static>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub type ChainResult<O, E> = StdResult<O, ChainError<E>>; | ||||||
|  | 
 | ||||||
| impl<T: 'static + Display + Debug> ChainError<T> { | impl<T: 'static + Display + Debug> ChainError<T> { | ||||||
|     #[cfg(feature = "fileline")] |     #[cfg(feature = "fileline")] | ||||||
|     pub fn new( |     pub fn new( | ||||||
|  | @ -39,11 +42,11 @@ impl<T: 'static + Display + Debug> ChainError<T> { | ||||||
|         Some(cause) |         Some(cause) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn find_cause<U: Error + 'static>(&self) -> Option<&(dyn Error + 'static)> { |     pub fn find_cause<U: Error + 'static>(&self) -> Option<&U> { | ||||||
|         let mut cause = self as &(dyn Error + 'static); |         let mut cause = self as &(dyn Error + 'static); | ||||||
|         loop { |         loop { | ||||||
|             if cause.is::<U>() { |             if cause.is::<U>() { | ||||||
|                 return Some(cause); |                 return cause.downcast_ref::<U>(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             match cause.source() { |             match cause.source() { | ||||||
|  | @ -53,7 +56,7 @@ impl<T: 'static + Display + Debug> ChainError<T> { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn find_kind<U: 'static + Display + Debug>(&self) -> Option<&ChainError<U>> { |     pub fn find_chain_cause<U: Error + 'static>(&self) -> Option<&ChainError<U>> { | ||||||
|         let mut cause = self as &(dyn Error + 'static); |         let mut cause = self as &(dyn Error + 'static); | ||||||
|         loop { |         loop { | ||||||
|             if cause.is::<ChainError<U>>() { |             if cause.is::<ChainError<U>>() { | ||||||
|  | @ -229,6 +232,9 @@ macro_rules! mstrerr { | ||||||
|     ( $t:path, $v:expr $(, $more:expr)* ) => { |     ( $t:path, $v:expr $(, $more:expr)* ) => { | ||||||
|         |e| cherr!(e, $t (format!($v, $( $more , )* ))) |         |e| cherr!(e, $t (format!($v, $( $more , )* ))) | ||||||
|     }; |     }; | ||||||
|  |     ( $v:expr $(, $more:expr)* ) => { | ||||||
|  |         |e| cherr!(e, format!($v, $( $more , )* )) | ||||||
|  |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[macro_export] | #[macro_export] | ||||||
|  | @ -245,138 +251,37 @@ macro_rules! derive_str_cherr { | ||||||
|                 write!(f, "{}({})", stringify!($e), self.0) |                 write!(f, "{}({})", stringify!($e), self.0) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         impl ::std::error::Error for $e {} | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[macro_export] | ||||||
|  | macro_rules! try_cherr_ref { | ||||||
|  |     ( $e:expr, $t:ident ) => { | ||||||
|  |         $e.downcast_ref::<ChainError<$t>>() | ||||||
|  |     }; | ||||||
|  |     ( $e:expr, $t:path ) => { | ||||||
|  |         $e.downcast_ref::<ChainError<$t>>() | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[macro_export] | ||||||
|  | macro_rules! try_cherr_mut { | ||||||
|  |     ( $e:expr, $t:ident ) => { | ||||||
|  |         $e.downcast_mut::<ChainError<$t>>() | ||||||
|  |     }; | ||||||
|  |     ( $e:expr, $t:path ) => { | ||||||
|  |         $e.downcast_mut::<ChainError<$t>>() | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub mod prelude { | pub mod prelude { | ||||||
|     pub use super::{cherr, derive_str_cherr, mstrerr, ChainError, ChainErrorDown}; |     pub use super::{ | ||||||
|  |         cherr, derive_str_cherr, mstrerr, try_cherr_mut, try_cherr_ref, ChainError, ChainErrorDown, | ||||||
|  |         ChainResult, | ||||||
|  |     }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod tests { | mod tests { | ||||||
|     use std::error::Error; |  | ||||||
|     use std::io::Error as IoError; |  | ||||||
|     use std::io::ErrorKind as IoErrorKind; |  | ||||||
|     use std::path::Path; |  | ||||||
| 
 |  | ||||||
|     use crate::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_config_pre(p: &str) -> Result<(), Box<Error>> { |  | ||||||
|         read_config(Path::new(p)).map_err(mstrerr!(AppError, "{}", p))?; |  | ||||||
|         Ok(()) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     #[test] |  | ||||||
|     fn test_chain_error() { |  | ||||||
|         for p in &[ |  | ||||||
|             "global.ini", |  | ||||||
|             "local.ini", |  | ||||||
|             "user.ini", |  | ||||||
|             "user2.ini", |  | ||||||
|             "user3.ini", |  | ||||||
|             "custom.ini", |  | ||||||
|             "essential.ini", |  | ||||||
|         ] { |  | ||||||
|             if let Err(e) = read_config_pre(p) { |  | ||||||
|                 let app_err = e.downcast_chain_ref::<AppError>().unwrap(); |  | ||||||
| 
 |  | ||||||
|                 match p { |  | ||||||
|                     &"global.ini" => { |  | ||||||
|                         assert!(app_err.find_kind::<ConfigFileError>().is_some()); |  | ||||||
|                         assert!(app_err.root_cause().unwrap().is::<IoError>()); |  | ||||||
|                     }, |  | ||||||
|                     _ => {} |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Harald Hoyer
						Harald Hoyer