From ed418cf9bfbe495c6aba25316f74580a7b7ad17f Mon Sep 17 00:00:00 2001 From: Kevin Herrera Date: Tue, 18 Jan 2022 05:23:36 +0000 Subject: [PATCH 1/5] Far better conversion for all std::error::Error errors. --- src/error.rs | 66 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/src/error.rs b/src/error.rs index ff2399e..7f2a73b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -68,7 +68,7 @@ //! No such file or directory (os error 2) //! ``` -use std::{fmt, io, process, sync}; +use std::{fmt, process}; /// A trait to add context to an error result. /// @@ -265,21 +265,29 @@ impl fmt::Display for Error { } } -impl From for Error { - fn from(error: io::Error) -> Self { - Self { - context: None, - message: Some(error.to_string()), - status: error.raw_os_error().unwrap_or(1), +impl From for Error { + fn from(error: T) -> Self { + let mut context = None; + let mut current = &error as &dyn std::error::Error; + let message; + + loop { + if let Some(next) = current.source() { + context + .get_or_insert_with(|| Vec::new()) + .push(current.to_string()); + + current = next; + } else { + message = Some(current.to_string()); + + break; + } } - } -} -impl From> for Error { - fn from(error: sync::PoisonError) -> Self { Self { - context: None, - message: Some(error.to_string()), + context, + message, status: 1, } } @@ -594,6 +602,38 @@ mod test { ); } + #[test] + fn from_error() { + fn generate_error() -> Result<()> { + fn source_error() -> Result<()> { + let _ = std::fs::File::open("/should/not/exist")?; + + Ok(()) + } + + source_error().context(|| "The lower level message.")?; + + Ok(()) + } + + let error = generate_error() + .context(|| "The higher level message.") + .unwrap_err(); + + assert_eq!( + error.context, + Some(vec![ + "The lower level message.".to_string(), + "The higher level message.".to_string() + ]) + ); + assert_eq!( + error.message, + Some("No such file or directory (os error 2)".to_string()) + ); + assert_eq!(error.status, 1); + } + #[test] fn result_context() { let err: Result<()> = Err(Error::default()).context(|| "The context message."); From 0d9c8e04d93851fc2b6a30489a0757c88f67995a Mon Sep 17 00:00:00 2001 From: Kevin Herrera Date: Tue, 18 Jan 2022 05:48:22 +0000 Subject: [PATCH 2/5] Preserving error code. --- src/error.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/error.rs b/src/error.rs index 7f2a73b..c6a4585 100644 --- a/src/error.rs +++ b/src/error.rs @@ -265,22 +265,34 @@ impl fmt::Display for Error { } } -impl From for Error { +impl From for Error { fn from(error: T) -> Self { let mut context = None; let mut current = &error as &dyn std::error::Error; let message; + let mut status = 1; + // Allow for error source traversal. loop { + // If not at the lowest level, capture the error as context. if let Some(next) = current.source() { context .get_or_insert_with(|| Vec::new()) .push(current.to_string()); current = next; + + // If at the lowest level, capture the message. } else { message = Some(current.to_string()); + // If std::io::Error, capture the OS error code as the status. + if let Some(other) = current.downcast_ref::() { + if let Some(code) = other.raw_os_error() { + status = code; + } + } + break; } } @@ -288,7 +300,7 @@ impl From for Error { Self { context, message, - status: 1, + status, } } } @@ -631,7 +643,7 @@ mod test { error.message, Some("No such file or directory (os error 2)".to_string()) ); - assert_eq!(error.status, 1); + assert_eq!(error.status, 2); } #[test] From 4814b523ad9692f8feb34e218d4de3289d256b81 Mon Sep 17 00:00:00 2001 From: Kevin Herrera Date: Tue, 18 Jan 2022 05:53:21 +0000 Subject: [PATCH 3/5] Properly handling Windows OS level error in testing. --- src/error.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/error.rs b/src/error.rs index c6a4585..7c4eb21 100644 --- a/src/error.rs +++ b/src/error.rs @@ -639,11 +639,24 @@ mod test { "The higher level message.".to_string() ]) ); - assert_eq!( - error.message, - Some("No such file or directory (os error 2)".to_string()) - ); - assert_eq!(error.status, 2); + + #[cfg(not(windows))] + { + assert_eq!( + error.message, + Some("No such file or directory (os error 2)".to_string()) + ); + assert_eq!(error.status, 2); + } + + #[cfg(windows)] + { + assert_eq!( + error.message, + Some("The system cannot find the path specified. (os error 3)".to_string()) + ); + assert_eq!(error.status, 3); + } } #[test] From b4e695d1e8613fa6cbf13c6c0836bee3d41bd478 Mon Sep 17 00:00:00 2001 From: Kevin Herrera Date: Tue, 18 Jan 2022 05:58:10 +0000 Subject: [PATCH 4/5] Making clippy stricter. --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7e464b9..1c9d68c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,4 +32,4 @@ jobs: uses: actions-rs/cargo@v1 with: command: clippy - args: --all-targets --all-features + args: --all-targets --all-features -- -D warnings From 8691a5f3583bf59f5ccd3342f205a8f0ad2e631e Mon Sep 17 00:00:00 2001 From: Kevin Herrera Date: Tue, 18 Jan 2022 05:58:30 +0000 Subject: [PATCH 5/5] Applying clippy suggestions. --- src/error.rs | 2 +- src/io.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/error.rs b/src/error.rs index 7c4eb21..5c167af 100644 --- a/src/error.rs +++ b/src/error.rs @@ -277,7 +277,7 @@ impl From for Error { // If not at the lowest level, capture the error as context. if let Some(next) = current.source() { context - .get_or_insert_with(|| Vec::new()) + .get_or_insert_with(Vec::new) .push(current.to_string()); current = next; diff --git a/src/io.rs b/src/io.rs index 363a9a1..5dc5ff1 100644 --- a/src/io.rs +++ b/src/io.rs @@ -529,7 +529,7 @@ mod test { assert_eq!(vec, b"test"); } else { - assert!(false, "Unexpected StreamKind."); + panic!("Unexpected StreamKind."); } }