1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

env: Move to "thiserror" + added errors test case (#7584)

Solved Issue #7535 : Removed parse_errors to follow other commands standard with thiserror
This commit is contained in:
ValentinBoudevin 2025-03-30 11:21:57 +02:00 committed by GitHub
parent 903fa6ae88
commit aea23408fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 231 additions and 195 deletions

1
Cargo.lock generated
View file

@ -2727,6 +2727,7 @@ dependencies = [
"clap",
"nix",
"rust-ini",
"thiserror 2.0.12",
"uucore",
]

View file

@ -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]

129
src/uu/env/src/env.rs vendored
View file

@ -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<string_parser::Error> 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<Vec<NativeIntString>> {
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 (':')"));
}
}

View file

@ -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<string_parser::Error> for ParseError {
fn from(value: string_parser::Error) -> Self {
Self::InternalError {
pos: value.peek_position,
sub_err: value,
}
}
}

View file

@ -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<bool, ParseError> {
fn check_and_replace_ascii_escape_code(&mut self, c: char) -> Result<bool, EnvError> {
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<Vec<NativeIntString>, ParseError> {
pub fn split(mut self) -> Result<Vec<NativeIntString>, EnvError> {
self.state_root()?;
Ok(self.words)
}
}
pub fn split(s: &NativeIntStr) -> Result<Vec<NativeIntString>, ParseError> {
pub fn split(s: &NativeIntStr) -> Result<Vec<NativeIntString>, EnvError> {
let split_args = SplitIterator::new(s).split()?;
Ok(split_args)
}

View file

@ -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()?;

View file

@ -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<Vec<OsString>, ParseError> {
fn split(input: &str) -> Result<Vec<OsString>, 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}'
))
);
}