use std::error;
use std::ffi;
use std::fmt;
#[derive(Debug, PartialEq)]
pub enum InvalidOsArg {
OsArgsContainInvalidUnicode {
index: usize,
os_arg: ffi::OsString,
},
}
impl fmt::Display for InvalidOsArg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match self {
InvalidOsArg::OsArgsContainInvalidUnicode { index, os_arg } => write!(
f,
"The command line arguments contains invalid unicode (index: {}, \
arguments: \"{}\")",
index,
String::from_utf8_lossy(os_arg.as_encoded_bytes()).escape_debug(),
),
}
}
}
impl error::Error for InvalidOsArg {}
#[cfg(not(windows))] #[cfg(test)]
mod tests_of_invalid_os_arg {
use super::*;
mod tests_of_os_args_contain_invalid_unicode {
use super::*;
use std::error;
use std::ffi;
#[test]
fn should_create_and_handles() {
let bad_input = b"Hello \xF0\x90\x80World";
let bad_os_str = unsafe { ffi::OsStr::from_encoded_bytes_unchecked(bad_input) };
let bad_os_string = bad_os_str.to_os_string();
let result: Result<(), InvalidOsArg> = Err(InvalidOsArg::OsArgsContainInvalidUnicode {
index: 12,
os_arg: bad_os_string.clone(),
});
match result {
Ok(_) => assert!(false),
Err(ref err) => {
assert_eq!(
format!("{err}"),
"The command line arguments contains invalid unicode (index: 12, \
arguments: \"Hello �World\")"
);
assert_eq!(
format!("{err:?}"),
"OsArgsContainInvalidUnicode { index: 12, os_arg: \"Hello \
\\xF0\\x90\\x80World\" }"
);
}
}
match result {
Ok(_) => assert!(false),
Err(ref err) => match err {
InvalidOsArg::OsArgsContainInvalidUnicode { index, os_arg } => {
assert_eq!(*index, 12);
assert_eq!(format!("{os_arg:?}"), "\"Hello \\xF0\\x90\\x80World\"");
}
},
}
match result {
Ok(_) => assert!(false),
Err(InvalidOsArg::OsArgsContainInvalidUnicode { index, os_arg }) => {
assert_eq!(index, 12);
assert_eq!(format!("{os_arg:?}"), "\"Hello \\xF0\\x90\\x80World\"");
}
}
}
#[test]
fn should_write_for_debug() {
let bad_input = b"Hello \xF0\x90\x80World";
let bad_os_str = unsafe { ffi::OsStr::from_encoded_bytes_unchecked(bad_input) };
let bad_os_string = bad_os_str.to_os_string();
let result: Result<(), InvalidOsArg> = Err(InvalidOsArg::OsArgsContainInvalidUnicode {
index: 12,
os_arg: bad_os_string.clone(),
});
match result {
Ok(_) => assert!(false),
Err(ref err) => {
assert_eq!(
format!("{err:?}"),
"OsArgsContainInvalidUnicode { index: 12, os_arg: \"Hello \
\\xF0\\x90\\x80World\" }"
);
}
}
}
#[test]
fn should_write_for_display() {
let bad_input = b"Hello \xF0\x90\x80World";
let bad_os_str = unsafe { ffi::OsStr::from_encoded_bytes_unchecked(bad_input) };
let bad_os_string = bad_os_str.to_os_string();
let result: Result<(), InvalidOsArg> = Err(InvalidOsArg::OsArgsContainInvalidUnicode {
index: 12,
os_arg: bad_os_string.clone(),
});
match result {
Ok(_) => assert!(false),
Err(ref err) => {
assert_eq!(
format!("{err}"),
"The command line arguments contains invalid unicode (index: 12, \
arguments: \"Hello �World\")"
);
}
}
}
#[test]
fn should_handle_as_dyn_std_error() {
fn returns_error() -> Result<(), InvalidOsArg> {
let bad_input = b"Hello \xF0\x90\x80World";
let bad_os_str = unsafe { ffi::OsStr::from_encoded_bytes_unchecked(bad_input) };
let bad_os_string = bad_os_str.to_os_string();
Err(InvalidOsArg::OsArgsContainInvalidUnicode {
index: 12,
os_arg: bad_os_string.clone(),
})
}
fn returns_dyn_std_error() -> Result<(), Box<dyn error::Error>> {
returns_error()?;
Ok(())
}
match returns_dyn_std_error() {
Ok(_) => assert!(false),
Err(err) => {
if let Some(os_arg_err) = err.downcast_ref::<InvalidOsArg>() {
match os_arg_err {
InvalidOsArg::OsArgsContainInvalidUnicode { index, os_arg } => {
assert_eq!(*index, 12);
assert_eq!(
format!("{:?}", os_arg),
"\"Hello \\xF0\\x90\\x80World\""
);
}
}
} else {
assert!(false);
}
}
}
}
}
}