From aea23408fd839e8f3316d5e5839bec439841af5d Mon Sep 17 00:00:00 2001 From: ValentinBoudevin <62927696+ValentinBoudevin@users.noreply.github.com> Date: Sun, 30 Mar 2025 11:21:57 +0200 Subject: [PATCH] env: Move to "thiserror" + added errors test case (#7584) Solved Issue #7535 : Removed parse_errors to follow other commands standard with thiserror --- Cargo.lock | 1 + src/uu/env/Cargo.toml | 1 + src/uu/env/src/env.rs | 129 +++++++++++++++++++++++++++--- src/uu/env/src/parse_error.rs | 55 ------------- src/uu/env/src/split_iterator.rs | 110 ++++++++++++------------- src/uu/env/src/variable_parser.rs | 61 +++++++------- tests/by-util/test_env.rs | 69 +++++++--------- 7 files changed, 231 insertions(+), 195 deletions(-) delete mode 100644 src/uu/env/src/parse_error.rs diff --git a/Cargo.lock b/Cargo.lock index dff6d65a4..445d7964e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2727,6 +2727,7 @@ dependencies = [ "clap", "nix", "rust-ini", + "thiserror 2.0.12", "uucore", ] diff --git a/src/uu/env/Cargo.toml b/src/uu/env/Cargo.toml index 9cb120f64..f1a50b8b9 100644 --- a/src/uu/env/Cargo.toml +++ b/src/uu/env/Cargo.toml @@ -19,6 +19,7 @@ path = "src/env.rs" [dependencies] clap = { workspace = true } rust-ini = { workspace = true } +thiserror = { workspace = true } uucore = { workspace = true, features = ["signals"] } [target.'cfg(unix)'.dependencies] diff --git a/src/uu/env/src/env.rs b/src/uu/env/src/env.rs index ee087b957..d99284330 100644 --- a/src/uu/env/src/env.rs +++ b/src/uu/env/src/env.rs @@ -6,7 +6,6 @@ // spell-checker:ignore (ToDO) chdir execvp progname subcommand subcommands unsets setenv putenv spawnp SIGSEGV SIGBUS sigaction pub mod native_int_str; -pub mod parse_error; pub mod split_iterator; pub mod string_expander; pub mod string_parser; @@ -40,6 +39,42 @@ use uucore::line_ending::LineEnding; use uucore::signals::signal_by_name_or_value; use uucore::{format_usage, help_about, help_section, help_usage, show_warning}; +use thiserror::Error; + +#[derive(Debug, Error, PartialEq)] +pub enum EnvError { + #[error("no terminating quote in -S string")] + EnvMissingClosingQuote(usize, char), + #[error("invalid backslash at end of string in -S")] + EnvInvalidBackslashAtEndOfStringInMinusS(usize, String), + #[error("'\\c' must not appear in double-quoted -S string")] + EnvBackslashCNotAllowedInDoubleQuotes(usize), + #[error("invalid sequence '\\{}' in -S",.1)] + EnvInvalidSequenceBackslashXInMinusS(usize, char), + #[error("Missing closing brace")] + EnvParsingOfVariableMissingClosingBrace(usize), + #[error("Missing variable name")] + EnvParsingOfMissingVariable(usize), + #[error("Missing closing brace after default value at {}",.0)] + EnvParsingOfVariableMissingClosingBraceAfterValue(usize), + #[error("Unexpected character: '{}', expected variable name must not start with 0..9",.1)] + EnvParsingOfVariableUnexpectedNumber(usize, String), + #[error("Unexpected character: '{}', expected a closing brace ('}}') or colon (':')",.1)] + EnvParsingOfVariableExceptedBraceOrColon(usize, String), + #[error("")] + EnvReachedEnd, + #[error("")] + EnvContinueWithDelimiter, + #[error("{}{:?}",.0,.1)] + EnvInternalError(usize, string_parser::Error), +} + +impl From for EnvError { + fn from(value: string_parser::Error) -> Self { + EnvError::EnvInternalError(value.peek_position, value) + } +} + const ABOUT: &str = help_about!("env.md"); const USAGE: &str = help_usage!("env.md"); const AFTER_HELP: &str = help_section!("after help", "env.md"); @@ -273,20 +308,28 @@ pub fn uu_app() -> Command { pub fn parse_args_from_str(text: &NativeIntStr) -> UResult> { split_iterator::split(text).map_err(|e| match e { - parse_error::ParseError::BackslashCNotAllowedInDoubleQuotes { pos: _ } => { - USimpleError::new(125, "'\\c' must not appear in double-quoted -S string") + EnvError::EnvBackslashCNotAllowedInDoubleQuotes(_) => USimpleError::new(125, e.to_string()), + EnvError::EnvInvalidBackslashAtEndOfStringInMinusS(_, _) => { + USimpleError::new(125, e.to_string()) } - parse_error::ParseError::InvalidBackslashAtEndOfStringInMinusS { pos: _, quoting: _ } => { - USimpleError::new(125, "invalid backslash at end of string in -S") + EnvError::EnvInvalidSequenceBackslashXInMinusS(_, _) => { + USimpleError::new(125, e.to_string()) } - parse_error::ParseError::InvalidSequenceBackslashXInMinusS { pos: _, c } => { - USimpleError::new(125, format!("invalid sequence '\\{c}' in -S")) + EnvError::EnvMissingClosingQuote(_, _) => USimpleError::new(125, e.to_string()), + EnvError::EnvParsingOfVariableMissingClosingBrace(pos) => { + USimpleError::new(125, format!("variable name issue (at {pos}): {}", e)) } - parse_error::ParseError::MissingClosingQuote { pos: _, c: _ } => { - USimpleError::new(125, "no terminating quote in -S string") + EnvError::EnvParsingOfMissingVariable(pos) => { + USimpleError::new(125, format!("variable name issue (at {pos}): {}", e)) } - parse_error::ParseError::ParsingOfVariableNameFailed { pos, msg } => { - USimpleError::new(125, format!("variable name issue (at {pos}): {msg}",)) + EnvError::EnvParsingOfVariableMissingClosingBraceAfterValue(pos) => { + USimpleError::new(125, format!("variable name issue (at {pos}): {}", e)) + } + EnvError::EnvParsingOfVariableUnexpectedNumber(pos, _) => { + USimpleError::new(125, format!("variable name issue (at {pos}): {}", e)) + } + EnvError::EnvParsingOfVariableExceptedBraceOrColon(pos, _) => { + USimpleError::new(125, format!("variable name issue (at {pos}): {}", e)) } _ => USimpleError::new(125, format!("Error: {e:?}")), }) @@ -771,4 +814,68 @@ mod tests { parse_args_from_str(&NCvt::convert(r#"-i A='B \' C'"#)).unwrap() ); } + + #[test] + fn test_error_cases() { + // Test EnvBackslashCNotAllowedInDoubleQuotes + let result = parse_args_from_str(&NCvt::convert(r#"sh -c "echo \c""#)); + assert!(result.is_err()); + assert_eq!( + result.unwrap_err().to_string(), + "'\\c' must not appear in double-quoted -S string" + ); + + // Test EnvInvalidBackslashAtEndOfStringInMinusS + let result = parse_args_from_str(&NCvt::convert(r#"sh -c "echo \"#)); + assert!(result.is_err()); + assert_eq!( + result.unwrap_err().to_string(), + "no terminating quote in -S string" + ); + + // Test EnvInvalidSequenceBackslashXInMinusS + let result = parse_args_from_str(&NCvt::convert(r#"sh -c "echo \x""#)); + assert!(result.is_err()); + assert!( + result + .unwrap_err() + .to_string() + .contains("invalid sequence '\\x' in -S") + ); + + // Test EnvMissingClosingQuote + let result = parse_args_from_str(&NCvt::convert(r#"sh -c "echo "#)); + assert!(result.is_err()); + assert_eq!( + result.unwrap_err().to_string(), + "no terminating quote in -S string" + ); + + // Test variable-related errors + let result = parse_args_from_str(&NCvt::convert(r#"echo ${FOO"#)); + assert!(result.is_err()); + assert!( + result + .unwrap_err() + .to_string() + .contains("variable name issue (at 10): Missing closing brace") + ); + + let result = parse_args_from_str(&NCvt::convert(r#"echo ${FOO:-value"#)); + assert!(result.is_err()); + assert!( + result + .unwrap_err() + .to_string() + .contains("variable name issue (at 17): Missing closing brace after default value") + ); + + let result = parse_args_from_str(&NCvt::convert(r#"echo ${1FOO}"#)); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("variable name issue (at 7): Unexpected character: '1', expected variable name must not start with 0..9")); + + let result = parse_args_from_str(&NCvt::convert(r#"echo ${FOO?}"#)); + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("variable name issue (at 10): Unexpected character: '?', expected a closing brace ('}') or colon (':')")); + } } diff --git a/src/uu/env/src/parse_error.rs b/src/uu/env/src/parse_error.rs deleted file mode 100644 index 84e5ba859..000000000 --- a/src/uu/env/src/parse_error.rs +++ /dev/null @@ -1,55 +0,0 @@ -// This file is part of the uutils coreutils package. -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. - -use std::fmt; - -use crate::string_parser; - -/// An error returned when string arg splitting fails. -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ParseError { - MissingClosingQuote { - pos: usize, - c: char, - }, - InvalidBackslashAtEndOfStringInMinusS { - pos: usize, - quoting: String, - }, - BackslashCNotAllowedInDoubleQuotes { - pos: usize, - }, - InvalidSequenceBackslashXInMinusS { - pos: usize, - c: char, - }, - ParsingOfVariableNameFailed { - pos: usize, - msg: String, - }, - InternalError { - pos: usize, - sub_err: string_parser::Error, - }, - ReachedEnd, - ContinueWithDelimiter, -} - -impl fmt::Display for ParseError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(format!("{self:?}").as_str()) - } -} - -impl std::error::Error for ParseError {} - -impl From for ParseError { - fn from(value: string_parser::Error) -> Self { - Self::InternalError { - pos: value.peek_position, - sub_err: value, - } - } -} diff --git a/src/uu/env/src/split_iterator.rs b/src/uu/env/src/split_iterator.rs index 379ec3bb7..3ed5779f4 100644 --- a/src/uu/env/src/split_iterator.rs +++ b/src/uu/env/src/split_iterator.rs @@ -20,11 +20,11 @@ use std::borrow::Cow; +use crate::EnvError; use crate::native_int_str::NativeCharInt; use crate::native_int_str::NativeIntStr; use crate::native_int_str::NativeIntString; use crate::native_int_str::from_native_int_representation; -use crate::parse_error::ParseError; use crate::string_expander::StringExpander; use crate::string_parser::StringParser; use crate::variable_parser::VariableParser; @@ -62,14 +62,14 @@ impl<'a> SplitIterator<'a> { } } - fn skip_one(&mut self) -> Result<(), ParseError> { + fn skip_one(&mut self) -> Result<(), EnvError> { self.expander .get_parser_mut() .consume_one_ascii_or_all_non_ascii()?; Ok(()) } - fn take_one(&mut self) -> Result<(), ParseError> { + fn take_one(&mut self) -> Result<(), EnvError> { Ok(self.expander.take_one()?) } @@ -94,7 +94,7 @@ impl<'a> SplitIterator<'a> { self.expander.get_parser_mut() } - fn substitute_variable<'x>(&'x mut self) -> Result<(), ParseError> { + fn substitute_variable<'x>(&'x mut self) -> Result<(), EnvError> { let mut var_parse = VariableParser::<'a, '_> { parser: self.get_parser_mut(), }; @@ -116,7 +116,7 @@ impl<'a> SplitIterator<'a> { Ok(()) } - fn check_and_replace_ascii_escape_code(&mut self, c: char) -> Result { + fn check_and_replace_ascii_escape_code(&mut self, c: char) -> Result { if let Some(replace) = REPLACEMENTS.iter().find(|&x| x.0 == c) { self.skip_one()?; self.push_char_to_word(replace.1); @@ -126,24 +126,24 @@ impl<'a> SplitIterator<'a> { Ok(false) } - fn make_invalid_sequence_backslash_xin_minus_s(&self, c: char) -> ParseError { - ParseError::InvalidSequenceBackslashXInMinusS { - pos: self.expander.get_parser().get_peek_position(), + fn make_invalid_sequence_backslash_xin_minus_s(&self, c: char) -> EnvError { + EnvError::EnvInvalidSequenceBackslashXInMinusS( + self.expander.get_parser().get_peek_position(), c, - } + ) } - fn state_root(&mut self) -> Result<(), ParseError> { + fn state_root(&mut self) -> Result<(), EnvError> { loop { match self.state_delimiter() { - Err(ParseError::ContinueWithDelimiter) => {} - Err(ParseError::ReachedEnd) => return Ok(()), + Err(EnvError::EnvContinueWithDelimiter) => {} + Err(EnvError::EnvReachedEnd) => return Ok(()), result => return result, } } } - fn state_delimiter(&mut self) -> Result<(), ParseError> { + fn state_delimiter(&mut self) -> Result<(), EnvError> { loop { match self.get_current_char() { None => return Ok(()), @@ -166,12 +166,12 @@ impl<'a> SplitIterator<'a> { } } - fn state_delimiter_backslash(&mut self) -> Result<(), ParseError> { + fn state_delimiter_backslash(&mut self) -> Result<(), EnvError> { match self.get_current_char() { - None => Err(ParseError::InvalidBackslashAtEndOfStringInMinusS { - pos: self.get_parser().get_peek_position(), - quoting: "Delimiter".into(), - }), + None => Err(EnvError::EnvInvalidBackslashAtEndOfStringInMinusS( + self.get_parser().get_peek_position(), + "Delimiter".into(), + )), Some('_') | Some(NEW_LINE) => { self.skip_one()?; Ok(()) @@ -181,18 +181,18 @@ impl<'a> SplitIterator<'a> { self.take_one()?; self.state_unquoted() } - Some('c') => Err(ParseError::ReachedEnd), + Some('c') => Err(EnvError::EnvReachedEnd), Some(c) if self.check_and_replace_ascii_escape_code(c)? => self.state_unquoted(), Some(c) => Err(self.make_invalid_sequence_backslash_xin_minus_s(c)), } } - fn state_unquoted(&mut self) -> Result<(), ParseError> { + fn state_unquoted(&mut self) -> Result<(), EnvError> { loop { match self.get_current_char() { None => { self.push_word_to_words(); - return Err(ParseError::ReachedEnd); + return Err(EnvError::EnvReachedEnd); } Some(DOLLAR) => { self.substitute_variable()?; @@ -221,12 +221,12 @@ impl<'a> SplitIterator<'a> { } } - fn state_unquoted_backslash(&mut self) -> Result<(), ParseError> { + fn state_unquoted_backslash(&mut self) -> Result<(), EnvError> { match self.get_current_char() { - None => Err(ParseError::InvalidBackslashAtEndOfStringInMinusS { - pos: self.get_parser().get_peek_position(), - quoting: "Unquoted".into(), - }), + None => Err(EnvError::EnvInvalidBackslashAtEndOfStringInMinusS( + self.get_parser().get_peek_position(), + "Unquoted".into(), + )), Some(NEW_LINE) => { self.skip_one()?; Ok(()) @@ -234,11 +234,11 @@ impl<'a> SplitIterator<'a> { Some('_') => { self.skip_one()?; self.push_word_to_words(); - Err(ParseError::ContinueWithDelimiter) + Err(EnvError::EnvContinueWithDelimiter) } Some('c') => { self.push_word_to_words(); - Err(ParseError::ReachedEnd) + Err(EnvError::EnvReachedEnd) } Some(DOLLAR) | Some(BACKSLASH) | Some(SINGLE_QUOTES) | Some(DOUBLE_QUOTES) => { self.take_one()?; @@ -249,14 +249,14 @@ impl<'a> SplitIterator<'a> { } } - fn state_single_quoted(&mut self) -> Result<(), ParseError> { + fn state_single_quoted(&mut self) -> Result<(), EnvError> { loop { match self.get_current_char() { None => { - return Err(ParseError::MissingClosingQuote { - pos: self.get_parser().get_peek_position(), - c: '\'', - }); + return Err(EnvError::EnvMissingClosingQuote( + self.get_parser().get_peek_position(), + '\'', + )); } Some(SINGLE_QUOTES) => { self.skip_one()?; @@ -273,12 +273,12 @@ impl<'a> SplitIterator<'a> { } } - fn split_single_quoted_backslash(&mut self) -> Result<(), ParseError> { + fn split_single_quoted_backslash(&mut self) -> Result<(), EnvError> { match self.get_current_char() { - None => Err(ParseError::MissingClosingQuote { - pos: self.get_parser().get_peek_position(), - c: '\'', - }), + None => Err(EnvError::EnvMissingClosingQuote( + self.get_parser().get_peek_position(), + '\'', + )), Some(NEW_LINE) => { self.skip_one()?; Ok(()) @@ -299,14 +299,14 @@ impl<'a> SplitIterator<'a> { } } - fn state_double_quoted(&mut self) -> Result<(), ParseError> { + fn state_double_quoted(&mut self) -> Result<(), EnvError> { loop { match self.get_current_char() { None => { - return Err(ParseError::MissingClosingQuote { - pos: self.get_parser().get_peek_position(), - c: '"', - }); + return Err(EnvError::EnvMissingClosingQuote( + self.get_parser().get_peek_position(), + '"', + )); } Some(DOLLAR) => { self.substitute_variable()?; @@ -326,12 +326,12 @@ impl<'a> SplitIterator<'a> { } } - fn state_double_quoted_backslash(&mut self) -> Result<(), ParseError> { + fn state_double_quoted_backslash(&mut self) -> Result<(), EnvError> { match self.get_current_char() { - None => Err(ParseError::MissingClosingQuote { - pos: self.get_parser().get_peek_position(), - c: '"', - }), + None => Err(EnvError::EnvMissingClosingQuote( + self.get_parser().get_peek_position(), + '"', + )), Some(NEW_LINE) => { self.skip_one()?; Ok(()) @@ -340,18 +340,18 @@ impl<'a> SplitIterator<'a> { self.take_one()?; Ok(()) } - Some('c') => Err(ParseError::BackslashCNotAllowedInDoubleQuotes { - pos: self.get_parser().get_peek_position(), - }), + Some('c') => Err(EnvError::EnvBackslashCNotAllowedInDoubleQuotes( + self.get_parser().get_peek_position(), + )), Some(c) if self.check_and_replace_ascii_escape_code(c)? => Ok(()), Some(c) => Err(self.make_invalid_sequence_backslash_xin_minus_s(c)), } } - fn state_comment(&mut self) -> Result<(), ParseError> { + fn state_comment(&mut self) -> Result<(), EnvError> { loop { match self.get_current_char() { - None => return Err(ParseError::ReachedEnd), + None => return Err(EnvError::EnvReachedEnd), Some(NEW_LINE) => { self.skip_one()?; return Ok(()); @@ -363,13 +363,13 @@ impl<'a> SplitIterator<'a> { } } - pub fn split(mut self) -> Result, ParseError> { + pub fn split(mut self) -> Result, EnvError> { self.state_root()?; Ok(self.words) } } -pub fn split(s: &NativeIntStr) -> Result, ParseError> { +pub fn split(s: &NativeIntStr) -> Result, EnvError> { let split_args = SplitIterator::new(s).split()?; Ok(split_args) } diff --git a/src/uu/env/src/variable_parser.rs b/src/uu/env/src/variable_parser.rs index bd7a9c265..2555c709f 100644 --- a/src/uu/env/src/variable_parser.rs +++ b/src/uu/env/src/variable_parser.rs @@ -5,7 +5,8 @@ use std::ops::Range; -use crate::{native_int_str::NativeIntStr, parse_error::ParseError, string_parser::StringParser}; +use crate::EnvError; +use crate::{native_int_str::NativeIntStr, string_parser::StringParser}; pub struct VariableParser<'a, 'b> { pub parser: &'b mut StringParser<'a>, @@ -16,28 +17,26 @@ impl<'a> VariableParser<'a, '_> { self.parser.peek().ok() } - fn check_variable_name_start(&self) -> Result<(), ParseError> { + fn check_variable_name_start(&self) -> Result<(), EnvError> { if let Some(c) = self.get_current_char() { if c.is_ascii_digit() { - return Err(ParseError::ParsingOfVariableNameFailed { - pos: self.parser.get_peek_position(), - msg: format!( - "Unexpected character: '{c}', expected variable name must not start with 0..9" - ), - }); + return Err(EnvError::EnvParsingOfVariableUnexpectedNumber( + self.parser.get_peek_position(), + c.to_string(), + )); } } Ok(()) } - fn skip_one(&mut self) -> Result<(), ParseError> { + fn skip_one(&mut self) -> Result<(), EnvError> { self.parser.consume_chunk()?; Ok(()) } fn parse_braced_variable_name( &mut self, - ) -> Result<(&'a NativeIntStr, Option<&'a NativeIntStr>), ParseError> { + ) -> Result<(&'a NativeIntStr, Option<&'a NativeIntStr>), EnvError> { let pos_start = self.parser.get_peek_position(); self.check_variable_name_start()?; @@ -46,10 +45,9 @@ impl<'a> VariableParser<'a, '_> { loop { match self.get_current_char() { None => { - return Err(ParseError::ParsingOfVariableNameFailed { - pos: self.parser.get_peek_position(), - msg: "Missing closing brace".into(), - }); + return Err(EnvError::EnvParsingOfVariableMissingClosingBrace( + self.parser.get_peek_position(), + )); } Some(c) if !c.is_ascii() || c.is_ascii_alphanumeric() || c == '_' => { self.skip_one()?; @@ -59,10 +57,11 @@ impl<'a> VariableParser<'a, '_> { loop { match self.get_current_char() { None => { - return Err(ParseError::ParsingOfVariableNameFailed { - pos: self.parser.get_peek_position(), - msg: "Missing closing brace after default value".into(), - }); + return Err( + EnvError::EnvParsingOfVariableMissingClosingBraceAfterValue( + self.parser.get_peek_position(), + ), + ); } Some('}') => { default_end = Some(self.parser.get_peek_position()); @@ -83,12 +82,10 @@ impl<'a> VariableParser<'a, '_> { break; } Some(c) => { - return Err(ParseError::ParsingOfVariableNameFailed { - pos: self.parser.get_peek_position(), - msg: format!( - "Unexpected character: '{c}', expected a closing brace ('}}') or colon (':')" - ), - }); + return Err(EnvError::EnvParsingOfVariableExceptedBraceOrColon( + self.parser.get_peek_position(), + c.to_string(), + )); } }; } @@ -110,7 +107,7 @@ impl<'a> VariableParser<'a, '_> { Ok((varname, default_opt)) } - fn parse_unbraced_variable_name(&mut self) -> Result<&'a NativeIntStr, ParseError> { + fn parse_unbraced_variable_name(&mut self) -> Result<&'a NativeIntStr, EnvError> { let pos_start = self.parser.get_peek_position(); self.check_variable_name_start()?; @@ -128,10 +125,7 @@ impl<'a> VariableParser<'a, '_> { let pos_end = self.parser.get_peek_position(); if pos_end == pos_start { - return Err(ParseError::ParsingOfVariableNameFailed { - pos: pos_start, - msg: "Missing variable name".into(), - }); + return Err(EnvError::EnvParsingOfMissingVariable(pos_start)); } let varname = self.parser.substring(&Range { @@ -144,15 +138,14 @@ impl<'a> VariableParser<'a, '_> { pub fn parse_variable( &mut self, - ) -> Result<(&'a NativeIntStr, Option<&'a NativeIntStr>), ParseError> { + ) -> Result<(&'a NativeIntStr, Option<&'a NativeIntStr>), EnvError> { self.skip_one()?; let (name, default) = match self.get_current_char() { None => { - return Err(ParseError::ParsingOfVariableNameFailed { - pos: self.parser.get_peek_position(), - msg: "missing variable name".into(), - }); + return Err(EnvError::EnvParsingOfMissingVariable( + self.parser.get_peek_position(), + )); } Some('{') => { self.skip_one()?; diff --git a/tests/by-util/test_env.rs b/tests/by-util/test_env.rs index 7a44b1877..18b6b67c1 100644 --- a/tests/by-util/test_env.rs +++ b/tests/by-util/test_env.rs @@ -1017,10 +1017,12 @@ mod tests_split_iterator { use std::ffi::OsString; - use env::native_int_str::{Convert, NCvt, from_native_int_representation_owned}; - use env::parse_error::ParseError; + use env::{ + EnvError, + native_int_str::{Convert, NCvt, from_native_int_representation_owned}, + }; - fn split(input: &str) -> Result, ParseError> { + fn split(input: &str) -> Result, EnvError> { ::env::split_iterator::split(&NCvt::convert(input)).map(|vec| { vec.into_iter() .map(from_native_int_representation_owned) @@ -1127,24 +1129,24 @@ mod tests_split_iterator { fn split_trailing_backslash() { assert_eq!( split("\\"), - Err(ParseError::InvalidBackslashAtEndOfStringInMinusS { - pos: 1, - quoting: "Delimiter".into() - }) + Err(EnvError::EnvInvalidBackslashAtEndOfStringInMinusS( + 1, + "Delimiter".into() + )) ); assert_eq!( split(" \\"), - Err(ParseError::InvalidBackslashAtEndOfStringInMinusS { - pos: 2, - quoting: "Delimiter".into() - }) + Err(EnvError::EnvInvalidBackslashAtEndOfStringInMinusS( + 2, + "Delimiter".into() + )) ); assert_eq!( split("a\\"), - Err(ParseError::InvalidBackslashAtEndOfStringInMinusS { - pos: 2, - quoting: "Unquoted".into() - }) + Err(EnvError::EnvInvalidBackslashAtEndOfStringInMinusS( + 2, + "Unquoted".into() + )) ); } @@ -1152,26 +1154,14 @@ mod tests_split_iterator { fn split_errors() { assert_eq!( split("'abc"), - Err(ParseError::MissingClosingQuote { pos: 4, c: '\'' }) - ); - assert_eq!( - split("\""), - Err(ParseError::MissingClosingQuote { pos: 1, c: '"' }) - ); - assert_eq!( - split("'\\"), - Err(ParseError::MissingClosingQuote { pos: 2, c: '\'' }) - ); - assert_eq!( - split("'\\"), - Err(ParseError::MissingClosingQuote { pos: 2, c: '\'' }) + Err(EnvError::EnvMissingClosingQuote(4, '\'')) ); + assert_eq!(split("\""), Err(EnvError::EnvMissingClosingQuote(1, '"'))); + assert_eq!(split("'\\"), Err(EnvError::EnvMissingClosingQuote(2, '\''))); + assert_eq!(split("'\\"), Err(EnvError::EnvMissingClosingQuote(2, '\''))); assert_eq!( split(r#""$""#), - Err(ParseError::ParsingOfVariableNameFailed { - pos: 2, - msg: "Missing variable name".into() - }), + Err(EnvError::EnvParsingOfMissingVariable(2)), ); } @@ -1179,26 +1169,25 @@ mod tests_split_iterator { fn split_error_fail_with_unknown_escape_sequences() { assert_eq!( split("\\a"), - Err(ParseError::InvalidSequenceBackslashXInMinusS { pos: 1, c: 'a' }) + Err(EnvError::EnvInvalidSequenceBackslashXInMinusS(1, 'a')) ); assert_eq!( split("\"\\a\""), - Err(ParseError::InvalidSequenceBackslashXInMinusS { pos: 2, c: 'a' }) + Err(EnvError::EnvInvalidSequenceBackslashXInMinusS(2, 'a')) ); assert_eq!( split("'\\a'"), - Err(ParseError::InvalidSequenceBackslashXInMinusS { pos: 2, c: 'a' }) + Err(EnvError::EnvInvalidSequenceBackslashXInMinusS(2, 'a')) ); assert_eq!( split(r#""\a""#), - Err(ParseError::InvalidSequenceBackslashXInMinusS { pos: 2, c: 'a' }) + Err(EnvError::EnvInvalidSequenceBackslashXInMinusS(2, 'a')) ); assert_eq!( split(r"\🦉"), - Err(ParseError::InvalidSequenceBackslashXInMinusS { - pos: 1, - c: '\u{FFFD}' - }) + Err(EnvError::EnvInvalidSequenceBackslashXInMinusS( + 1, '\u{FFFD}' + )) ); }